美文网首页PyQt5css
CSS 技巧收录

CSS 技巧收录

作者: 西山以南 | 来源:发表于2019-06-13 00:29 被阅读0次

    【本文会持续更新!】

    1、color 影响 border-color

    当只设置元素的边框宽度和样式时,边框的颜色会取当前元素 color 属性的计算值。

    <div style="color: blue;border: 1px solid;">这里设置了 border,但不指定 border-color</div>
    

    瞧瞧该实例元素的 border-color 属性的计算值:

    可以看到,border-color 属性未设置值时为 initial 关键字,代表取该属性的默认值。那么,为什么这里取的是 color 属性的值而非浏览器对 border-color 的默认值(如果有的话)呢?

    因为 border-color 属性的默认值就是 currentColor 关键字(CSS 3),也就是当前元素的 color 属性的计算值,详见 border-color | MDN

    color 前景色

    MDN 中对 color 属性是这样介绍的:

    The color property sets the foreground color of an element's text content, and its decorations. It doesn't affect any other characteristic of the element

    翻译过来就是,color 属性设置元素文本内容的 前景色修饰

    HTML 元素的前景色包括:

    • 字体颜色,也就是狭义上的 color
    • border-color,边框的颜色;
    • outline-color,轮廓的颜色;
    • box-shadow,阴影的颜色;
    • text-shadow,文本阴影的颜色;

    以及文本修饰中的 text-decoration-color,下划线的颜色。

    <head>
      <style>
        p {
          color: blue;
          max-width: 500px;
        }
      </style>
    </head>
    <body>
      <p>这里没有做任何处理</p>
      <p style="border: 1px solid;">这里设置了 border,但不指定 border-color</p>
      <p style="outline: 1px solid;">这里设置了 outline,但不指定 outline-color</p>
      <p style="text-decoration: underline;">这里设置了 text-decoration,但不指定 text-decoration-color</p>
      <p style="box-shadow: 0 1px 2px 0;">这里设置了 box-shadow,但不指定颜色</p>
      <p style="text-shadow: 10px 10px 2px;">这里设置了 text-shadow,但不指定颜色</p>
    </body>
    

    2、移动端 H5 禁止显示系统菜单

    当在移动端 H5 上长按一个目标元素时,浏览器会弹出一个关于目标元素的菜单信息。请看下面针对文本元素的实例:

    <span>这是一段文字,请在移动端长按</span>
    

    在某些场景下,我们并不希望浏览器弹出这样的菜单,应该怎么做呢?我在网上搜罗了几个常见方案:

    • 通过 -webkit-touch-callout 属性禁用 callout【无效】

      -webkit-touch-callout: none;
      

      -webkit-touch-callout 属性的兼容性非常差,之前只有在 Safari 浏览器上可用。而 现在应该是被废弃了,亲测在 ios Safari 浏览器上不起效Can I use 上也已经搜索不到了。

    • JS 屏蔽 contextmenu 事件的默认行为【无效】

      $elm.addEventListener('contextmenu', (e) => {
        e.preventDefault();
      });
      

      当用户尝试打开上下文菜单(通常是鼠标右键单击)时,contextmenu 事件会被触发,我们可以通过 preventDefault() 方法来屏蔽菜单的显示。那么这种方法是否适用于移动端 h5 呢?

      答案是否定的。不妨来看看 contextmenu 事件的兼容性:

      so,网上的部分教程就不要再误人子弟了。

    • 通过 user-select 属性让元素不可选中【有效】

      -webkit-user-select: none;
      -moz-user-select: none; 
      -ms-user-select: none;
      -o-user-select: none;
      user-select: none;
      

      在移动端,若用户不可选中元素,自然也就不能通过长按调起默认菜单了。但需要注意的是,user-select: none 在部分浏览器(如 Safari)中会使 <input><textarea> 等表单元素失效

    • JS 屏蔽 touchstart 事件的默认行为【有效】

      $elm.addEventListener('touchend', (e) => {
        e.preventDefault();
      });
      

      此方案和使用 user-select 是一样的原理,但同样 需要注意禁止默认行为所带来的负面影响,譬如作用于可滚动元素时。

    所有方案的测试情况见:https://codepen.io/JunreyCen/pen/rEBYPV

    总结一下,移动端的兼容性一直是非常棘手的问题,各种手机操作系统、各种浏览器应用没有一套统一的 web 标准,都喜欢 “各抒己见”。也因此,上面提及的方案在某些型号手机的浏览器中(譬如 Oppo 自带的浏览器)依然是不起作用的,这种情况下开发者只能 “见招拆招”,无招可使时也只能择 “较优解” 了。


    3、文本溢出显示省略号

    我们经常遇到单行文本溢出时显示省略号的场景,那多行文本的类似处理该如何实现?

    单行文本

    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;      /* 文本不换行 */
    

    多行文本

    多行文本溢出时,最后一行截断并显示省略号。这里提供两种实现方式:

    • 使用 line-clamp 属性

      line-clamp 是一个不规范的属性,没有出现在 CSS 规范草案中。而且,它必须结合旧版的 flexbox(伸缩盒)模型才起作用。

      overflow: hidden;
      display: -webkit-box;           /* 旧版伸缩盒模型 */
      display: -moz-box;
      -webkit-box-orient: vertical;   /* 子元素垂直排列 */
      -moz-box-orient: vertical;
      -webkit-line-clamp: 2;          /* 块元素显示的文本行数 */
      -moz-line-clamp: 2;
      

      如下图所示,line-clamp 在兼容性方面还是有点缺陷的。

      除此之外还需要注意的是,autoprefixer 等预处理插件会自动删除一些旧的样式属性(包括 -webkit-box-orient 属性),所以使用这种方式时要对 autoprefixer 插件进行配置,详见这个 issue

    • JS + CSS 手动加省略号

      处理流程:

      1. 元素的 height 值设置为 line-height 值的整数倍n
      2. JS 获取元素的文本节点高度(scrollHeight),若高度\geq n+1line-height 值则视为文本溢出;
      3. 文本溢出时,于元素右下方显示省略号,否则不显示;
      <style>
      #ellipsis {
        position: relative;
        display: block;
        overflow: hidden;
        line-height: 20px;
        height: 40px;           /* height 为整数倍 line-height */
        word-break: break-all;  /* 使文本填充满容器,利于省略号和文本的衔接 */
      }
      .show-ellipsis {
        padding-right: 12px;    /* 给省略号腾出空间 */
      }
      .show-ellipsis:after {
        content: '...';
        position: absolute;
        right: 0;
        bottom: 0;
      } 
      </style>
      
      <p id="ellipsis">JS 和 CSS 设置多行文本字数超出时最后一行显示省略号,JS 和 CSS 设置多行文本字数超出时最后一行显示省略号</p>
      
      <script>
        const $elm = document.getElementById('js-ellipsis');
        const style = window.getComputedStyle($elm);
        const limitHeight = +style.height.replace('px', '') + +style.lineHeight.replace('px', '');
        if ($elm.scrollHeight >= limitHeight) {
          // 文本溢出则显示省略号
          $elm.className = 'show-ellipsis';
        }
      </script>
      

      这种实现方式基本不存在兼容性问题(除了低版本 IE 浏览器),但效果肯定比不上 line-clamp 的方式,只能静待 W3C 制订一套规范的处理方案了。


    4、图像自适应

    我们写页面的时候经常会遇到,获取的图片尺寸与我们所期待的渲染尺寸不符。譬如在渲染用户头像的场景下,我们往往希望用户上传的图片都是统一的正方形尺寸,然而用户给的可能是这样的:

    常见的处理方式是 适当的剪裁使图片填满容器而不被拉伸,我们可以利用背景图(background-size / background-position)来实现:

    <style>
    .avatar {
      width: 200px;
      height: 200px;
      border: 2px solid #07C160;
      background: url('./images/captain.jpeg') no-repeat;
      background-size: cover;
      background-position: center; 
    }
    </style>
    <div class="avatar"></div>
    

    CSS 3 中提供了新的属性:object-fit,可以对 <img> 标签作宽高自适应处理,效果类似于 background-size 属性。

    object-fit 提供了5个取值:

    • none:内容保持原有尺寸;
    • contain:内容保持宽高比地缩放,内容和容器的宽高比不匹配时会 留下白边
    • cover:内容保持宽高比地填满容器,内容和容器的宽高比不匹配时会 被裁剪
    • fill:内容刚好填满容器,内容和容器的宽高比不匹配时会 被拉伸
    • scale-down:内容尺寸和 nonecontain 中的一个相同,最终会显示尺寸较小的那个;

    background-size 和 object-fit 的效果对比

    同样的,background-positionobject-position 的作用类似,比较明显的区别在于:

    background-position 的默认值是 0% 0%,而 object-position 的默认值是 50% 50%

    object-fit 的意义

    • 解放了 background-image 的能力;
      譬如可以同时利用 background-image<img> 标签完成图片的堆叠等。
    • object-fit 对所有 可替换元素 都有效;
      常见的可替换元素包括:<iframe><video><embed><img><input type="image">

    兼容性

    额,如果要兼容 IE 浏览器的话,还是乖乖用背景图的方式把。


    5、块元素等比缩放

    现在的网页开发都讲究响应式设计,以使在各种尺寸的设备上也能保持良好的 UI 呈现。在响应式布局中,我们经常需要实现随网页视窗宽度动态变化的元素,尤其是支持等比缩放的元素。

    比较传统的做法,是通过 JS 监听 resize 事件,动态获取容器的宽度然后调整元素的宽高。这里提供一种纯 CSS 实现的方式,主要利用的是 padding 属性的百分比取值

    padding 属性的百分比取值是相对于其包含块的宽度。

    所以,当包含块的宽度发生变化时,子元素的 padding 属性的计算值会随之发生变化,也就是说子元素的总宽高都会被改变,且与包含块宽度成正比。

    <style>
    .wrapper {
      width: 200px;
      height: 300px;
      border: 2px solid #07C160;
    }
    .content {
      padding: 50%;
      width: 0;
      height: 0;
      background-color: #FA5151;
    }
    </style>
    
    <div class="wrapper">
      <div class="content"></div>
    </div>
    

    接下来的工作,只需要让目标元素的宽高参考于 padding 子元素的宽高,就完成了元素的等比缩放。我们可以利用 绝对定位 来实现。

    这里实现一个宽高比为 1:2、宽度保持为容器\frac{1}{2}的等比缩放元素:

    <style>
    .wrapper {
      width: 20%;
      height: 40%;
      border: 2px solid #07C160;
    }
    .container {
      position: relative;
      padding: 50%;
      width: 0;
      height: 0;
    }
    .content {
      position: absolute;
      top: 0;
      left: 0;
      width: 50%;
      height: 100%;
      background-color: #FA5151;
    }
    </style>
    
    <div class="wrapper">
      <div class="container">
        <div class="content"></div>
      </div>
    </div>
    

    为了突出演示效果,稍微 “修饰” 了一下:

    需要体验 Demo 的请跳转:https://codepen.io/JunreyCen/pen/agzoyG


    6、垂直外边距合并

    当两个垂直外边距邻接时,会合并成一个外边距。只有普通文档流中块元素的垂直外边距才会发生合并,不在同一个 BFC 内(譬如行内元素、浮动元素、绝对定位等)的垂直外边距不会合并,水平方向的外边距也不会合并

    通常发生外边距合并的场景有:

    • 相邻的两个块元素,邻接的上/下外边距发生合并

      图片摘自 http://www.w3school.com.cn/css/css_margin_collapsing.asp

      发生合并时外边距的计算规则:

      • 两个外边距都是正数时,取两者中的较大值;
      • 两个外边距一正一负时,取两者之和;
      • 两个外边距都是负数时,比较两者的绝对值大小,谁大取谁;
    • 无内边距(padding)和边框(border)的父元素的垂直外边距会与子元素的垂直外边距合并

      图片摘自 http://www.w3school.com.cn/css/css_margin_collapsing.asp
    • 无内边距(padding)、边框(border)和内容(content)的空元素的上/下外边距会合并

      图片摘自 http://www.w3school.com.cn/css/css_margin_collapsing.asp

    这里提供一个完整 Demo:https://codepen.io/JunreyCen/pen/zVxPWX


    7、行内(块)元素空隙

    试试执行这段代码:

    <img src="./images/captain.jpeg" width="200">
    <img src="./images/captain.jpeg" width="200">
    

    奇怪,两张图片之间出现了一道缝隙……

    这是因为 img 元素默认会被渲染成行内元素(display: inline;),而上述代码中两个 <img> 之间其实是存在一个 换行符 (以及若干个 制表符)的,这些都会被渲染成一个空白格,也就导致了缝隙的产生。

    解决办法有俩:

    • 写 HTML 代码的时候避免行内元素间的空格、换行符等特殊字符;
      <img src="./images/captain.jpeg" width="200"><img src="./images/captain.jpeg" width="200">
      
    • 把行内元素所在行的字体大小设为 font-size: 0;
      <style>
      body { font-size: 0; }
      </style>
      
      <img src="./images/captain.jpeg" width="200">
      <img src="./images/captain.jpeg" width="200">
      

    PS:行内块元素(display: inline-block)也会存在同样的问题。


    8、pointer-events: none;

    pointer-events 属性可以指定元素是否可以成为鼠标事件的 target ,通俗点讲就是该元素是否可以接收鼠标事件。

    pointer-events 属性有多种取值,详见 MDN。这里着重介绍取值 none

    pointer-events: none; 指定元素及其后代元素不会成为鼠标事件的 target,父元素不受影响。

    实验 Demo

    实验内容:三层 DOM 元素都监听了鼠标点击事件,其中 target 节点设置了 pointer-events: none,点击 child 元素,看看有哪层元素可以响应点击事件。

    <div class="parent" onclick="alert('parent')">
      <div class="target" onclick="alert('target')">
        <div class="child" onclick="alert('child')"></div>
      </div>
    </div>
    

    左边不作处理的实例会 alert 三次;而右边的实例只会 alert 一次,内容为 parent

    应用场景

    • 同层元素点击穿透

      我们在写 UI 基础组件时,多多少少会接触到 Field 输入框组件。比如下面的实例,需求是满足 0.5px 边框 + input 输入框

      <style>
      .field {
        position: relative;
        width: 250px;
        height: 50px;
        text-align: center;
      }
      .field:after {
        position: absolute;
        top: -50%;
        left: -50%;
        right: -50%;
        bottom: -50%;
        content: '';
        border: 1px solid #ccc;
        transform: scale(0.5);
      }
      </style>
      
      <div class="field">
        <input type="text" placeholder="请输入">
      </div>
      

      你会发现,左边的输入框无法聚焦。这其实跟 0.5px 边框的实现方式有关,实例中利用伪元素 :after 制造了一个2倍尺寸的子元素,然后通过 transform: scale(0.5) 缩放,从而实现 0.5px 边框。然而,**这个伪元素和 input 输入框属于同层元素,根据渲染的先后顺序伪元素是层叠于输入框之上的,所以鼠标点击事件是无法被输入框捕获的。

      我们只需要给伪元素设置 pointer-events: none;,使其无法成为鼠标事件的 target,input 输入框就可以成功被聚焦。

    • 阻止 :hover、:active 等鼠标行为状态的触发

      设置了 pointer-events: none; 的元素无法响应鼠标事件,自然也就无法触发相关的状态了。

    想体验实例的请访问:https://codepen.io/JunreyCen/pen/NZqKOx


    9、:first-child 和 :first-of-type 的区别

    • :first-child
      匹配其父元素的符合特定类型的首个子元素。条件更为苛刻,需要满足 首个子元素 + 符合特定类型

    • :first-of-type
      匹配其父元素的符合特定类型的第一个元素。条件较为宽松,在满足 符合特定类型 的范畴下寻找第一个元素即可。

    <style>
      .group-1 h2:first-child,
      .group-1 h3:first-child,
      .group-2 h2:first-of-type,
      .group-2 h3:first-of-type {
        color: #FA5151;
      }
    </style>
    
    <div class="group-1">
      <h2>父元素的第一个元素,第一个 h2 元素</h2>
      <h3>父元素的第二个元素,第一个 h3 元素</h3>
    </div>
    <div class="group-2">
      <h2>父元素的第一个元素,第一个 h2 元素</h2>
      <h3>父元素的第二个元素,第一个 h3 元素</h3>
    </div>
    

    10、当心分号 ;

    我们都知道,在样式表的声明块({...})内,样式声明之间会用分号隔开,这是因为引擎在解析时,每条声明之间的空格(包括换行符等)会被忽略:

    <style>
    div {
      color: red;
      font-size: 20px;
    }
    </style>
    <div>content</div>
    

    那如果,分号写在声明块之外呢?

    这相当于告诉引擎,样式表解析到这里就结束了,后面的东西就不用管了。来看看这个 demo:

    <style>
    div {color: red};
    .ctn-1 {color: blue}
    .ctn-2 {font-weight: 600}
    </style>
    <div id="ctn-1">蓝色字体</div>
    <div id="ctn-2">加粗字体</div>
    

    遇到类似的面试题时,就要注意仔细看别被 “坑” 了~

    相关文章

      网友评论

        本文标题:CSS 技巧收录

        本文链接:https://www.haomeiwen.com/subject/lmnotctx.html