Better

Ethan的博客,欢迎访问交流

CSS之我想更懂你

记录在CSS的使用过程中,越来越深入理解的一些具体应用的积累与总结,持续更新!

等比缩放

最近碰到一个使用CSS绘制正方形的问题,你可能会说这个有什么难得,我想说我的具体需求是一行放3个元素,此时每个元素都要是一个正方形,且自适应手机,手机屏幕越宽,正方形也就越大。项目中使用padding-top解决这个问题。

CSS3中新增弹性盒子模型之后,简直就是CSS前进路上的一大步,对于本人来说,简直就是一个利器,以至于在页面布局的时候第一反应总是使用弹性盒子,以至于那些能用CSS2解决的布局知识,都被我抛弃在脑后了,其实我觉得这也不好吧,因为在PC上极有可能碰见兼容性问题,即便一些问题可以通过增加前缀的方式解决,由于目前主要工作内容为hybird app开发,在移动端兼容性问题并不是那么突出,可能很多原因都是由于手机迭代比较快吧。

存在问题

之前的解决办法为书写了一个heightEqualWidth指令,指令的代码很简单,具体如下:

.directive('heightEqualWidth', ["$timeout", function ($timeout) {
    return {
      restrict: 'AE',
      link: function (scope, element) {
        $timeout(function () {
          element[0].style.height = element[0].offsetWidth + 'px';
        });
      }
    }
  }])

这里存在的问题是一开始元素是没有高度的,在使用js修改高度之前,页面可能就完成了绘制,同时由于容器是用来绘制canvas的原因,子元素变大,可父元素并没有变大,这里猜测canvas容器不能动态设定高度值,页面可能会错乱。

百分比参照

margin、padding使用百分比时候参照物的问题

当父元素有宽度的时候,margin与padding的百分比都是相对于其父元素的width而言,padding/margin-top/bottom并不依赖于父元素的height。

绝对定位时top、left百分比问题

不管是absolute或是relative定位,当父元素高度,宽度已知时,left是相对于父元素的宽度width,top是相对于父元素的高度height。

transform:translate(10%,10%)

参照物是要偏移对象本身的宽度widht与height而不是其父元素。

问题解决

有了padding百分比参照物为父容器的宽度时,项目中碰到了问题也就有了新思路,设置父元素的样式如下:

.container{
    padding-top: 33%;
    position: relative;
}

设置一个子元素作为中间层充满父元素,样式如下:

.middle{
    position: absolute;
    top: 0;
    bottom: 10px;
    left: 0;
    right: 0;
}

此时中间层的宽高平分给三个子元素,这样一来,三个子元素的就表现为一个自适应宽度的正方形啦,是不是很6!

计算属性

CSS新增的取值函数,主要用户动态计算长度值,将一些工作中需要使用js才能解决的问题,通过这个函数也可以解决了,参数可以是百分比、em、px和rem单位值,如width: calc(100% - 22px)。甚至可以是vw或者vh,分别表示窗口的宽度和高度,如width: calc(100vw - 100px),表示宽度为窗口宽度减去100px。v表示viewport的意思,不知道你有没有惊讶,反正我知道这玩意的时候我是很惊讶的,哈哈。

vw和vh是相对窗口而言,这个很明显,那么使用%比的时候是相对什么而言呢。空说无凭,写个demo测试下就好啦,第一直觉%应该是相对父元素而言,可是会不会和absolute定位一样,是相对第一个具有相对定位属性的父元素而言呢。demo结果表明,%相对父元素而言,且父元素并没有设置相对定位,流式定位也是可以滴。

calc()函数支持 +, -, *, / 运算,可以单一单位 或者 混合单位使用。但是使用中注意运算符号前后需要空格。

盒模型

正常情况下我们设置的容器的宽度和高度,是设置其content的宽高,容器的实际宽高应为content+padding+border。很多时候由于这种情况下,容易造成盒子的溢出,解决移除问题可以通过calc函数解决,也可以通过box-sizing设置计算模式。

语法 content-box | border-box | inherit

  • content-box:缺省模式,css设置宽高即为内容区域的宽高,不包括padding和border
  • border-box:css设置宽高为content+padding+border

有些人说还有一个padding-box属性,不知道是不是网友想当然还是咋滴,觉得padding-box应该是content+padding。但是实际上我在google浏览器上测试,并且是带有前缀的方式下,padding-box都是没有效果诶。

文本处理

文本溢出显示省略号

text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap

允许指定行数,超过显示省略号

display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
overflow:hidden

最近在vue项目中发现设置-webkit-box-orient:vertical后,代码总是不生效,经查阅发现是autoprefixer的一个小bug,autoprefixer不仅会帮你加-webkit-之类的prefixer, 它还会帮你删除你自己写在 css/sass/less里的样式,关闭autoprefixer的自动删除功能才可以生效

/*! autoprefixer: off */
-webkit-box-orient: vertical;
/* autoprefixer: on */

或者你可以通过增加remove: false这个配置项,全局关闭自动移除功能

postcss([ autoprefixer({ remove: false }) ]);

对于这两个文本处理方式,使用非常频繁,但是并不好记,写起来还啰嗦,我们可以通过 sass 的 mixin 帮助我们简写

// 不换行
@mixin no-wrap {
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
}

// 扩展点击区域
@mixin extend-click {
    position: relative;
    &::before {
        content: '';
        position: absolute;
        top: -10px;
        left: -10px;
        right: -10px;
        bottom: -10px;
    }
}

@mixin line-number($n: 2) {
    display: -webkit-box;
    /*! autoprefixer: off */
    -webkit-box-orient: vertical;
    /* autoprefixer: on */
    -webkit-line-clamp: $n;
    overflow: hidden;
}

设置了超过两行显示省略号后,如果某些内容只有一行,在流式布局下,这样样式就看上去不对齐,如何保证即使一行内容也有两行的高度呢,这里有个妙用记录一下,即加上如下css

line-height: 1.4em;
min-height: 2.8em;

这里主要利用了em单位相对属性的特点。

内联盒模型

font-size:0妙用

可以用font-size:0来清除间距。比如inline-block的元素之间会受空白区域的影响,也就是元素之间差不多会有一个字符的间隙。如果在同一行内有4个25%相同宽度的元素,会导致最后一个元素掉下来。你可以利用元素浮动float,或者压缩html,清除元素间的空格来解决。但最简单有效的方法还是设置父元素的font-size属性为0。

奇怪的IMG

使用DIV包裹图片,DIV比其包裹的img要大:需要把img设置为block,原因:img是一种类似text的元素,在结束的时候,会在末尾加上一个空白符,所以就会多出大约3px

overflow清除浮动

除了著名的clearfix清除浮动类,利用overflow属性也可以清除浮动。

@mixin clearfix() {
  &::after {
    display: block;
    clear: both;
    content: "";
  }
}

overflow除了定义溢出元素内容区的内容会如何处理外,还可以做一些有用的事,如:

  • 创建块格式化上下文(BFC:Block Formatting Contexts)
  • 清除浮动

禁用事件

这是一个很神奇的熟悉哈,找了很久才找到工作中碰到的问题,在Ionic中,模态框出现后会在body元素上添加modal-open样式,内容为pointer-events: none;,导致我在模态框的基础上又出现一个ActionSheet组件,但是ActionSheet却无法响应,甚至审查元素都只能直接定位到模态框的DOM,可以我明明设置我的ActionSheet的z-index比模态框高呀!这是怎么回事呢?后来发现模态框之所以能响应事件,是因为模态框添加了pointer-events: auto;属性,因此当我在ActionSheet上同样重置pointer-events属性为auto时,一切就都很美好了!

pointer-event属性更像是一个JavaScript事件,利用该属性,可以做如下的事情:

  • 阻止任何点击动作的执行
  • 使链接显示为默认光标(cursor:default)
  • 阻止触发hover和active状态
  • 阻止JavaScript点击事件的触发

超牛的 pointer-event(update in 20210327

  • auto:与未指定时的表现效果相同
  • none:除了指示该元素不是鼠标事件的目标之外,值 none 表示鼠标事件“穿透”该元素并且指定该元素“下面”的任何东西。

指定为 none 值在有些时候能够发挥巨大的威力,比如你需要在 canvas 上操作,最终会有些效果需要使用到 dom,比如显示鼠标跟随的 tooltip,这时候你就可以设置一个 div 盖在 canvas 上,设置 pointer-event 为 none 值,这样还是可以在 canvas 上绑定事件。

移动端CSS

fixed布局在移动端会有各种各样的问题,还是尽量避开。

解决移动端点击事件延迟(300ms):touch-action: manipulation;

禁止长按文本选中:user-select:none;

禁止触摸点击阴影:-webkit-tap-highlight-color: transparent;

禁止输入框浏览器默认行为:-webkit-appearance:none;

禁止长按弹出列表栏:-webkit-touch-callout:none;

滚动优化

在移动端,如果仅设置了 overflow:auto|scroll,手指离开屏幕就会立即停止滚动,这对于移动端而言很不友好。

控制元素在移动设备上是否使用滚动回弹效果:-webkit-overflow-scrolling

  • auto:使用普通滚动, 当手指从触摸屏上移开,滚动会立即停止。
  • touch;使用具有回弹效果的滚动, 当手指从触摸屏上移开,内容会继续保持一段时间的滚动效果。继续滚动的速度和持续的时间和滚动手势的强烈程度成正比。同时也会创建一个新的堆栈上下文。

在实际使用中,碰到z-index失效的BUG,在这里列举它可能存在的问题

  • 滚动中 scrollTop 属性不会变化
  • 手势可穿过其他元素触发元素滚动
  • 滚动时暂停其他 transition
  • 布局抖动
  • 偶尔卡住或不能滑动
  • 这个堆叠上下文会导致下面子元素z-index失效。解决办法:添加 overflow:hidden

追踪用户

CSS 是可以出发请求的,因此我们可以使用 CSS 追踪用户相关数据,甚至可以通过 CSS 创建 Key Logger 监听用户的密码。

更多资料



留言