CSS世界中那些说起来很冷的知识

20,183 阅读19分钟

读书使我快乐-哈哈

最近读了张鑫旭的新书《CSS世界》收获了不少奇技淫巧和对CSS的深度理解

也正值个人在公司内部进行部分章节的内容分享,于是顺带着直接把我即将分享的内容先给大家过过目了,就当省去了大家买了书后,无暇顾及观看的尴尬吧!

本书的最后三章分别是

  • 元素的显示与隐藏
  • 用户界面样式
  • 流向的改变

下面我就直接进入主题,开始对每一章节进行一个非系统的分享了

元素的显示与隐藏

使用CSS让元素不可见的方法很多,剪裁、定位到屏幕外、透明度变化等都是可以的。虽然它们都是肉眼看不见,但背后却在多个维度上都有差别

下面是总结的一些比较好的隐藏实践,大家一起来根据实际开发场景来选择合适的使用

比较好的隐藏实践

  • 不占空间,不渲染 使用script
    <script type="text/html">
        <!-- 图片是不会发送请求的 -->
        <img src="1.jpg" />
        <!-- 如果想嵌套需要借助textarea了 -->
        <textarea style="display: none;">
            <img src="2.png" />
        </textarea>
    </script>
    
  • 不占空间,资源可以加载,DOM可访问 使用display:none
    <div id="box">成都</div>
        <script>
            let oBox = document.getElementById('box');
            console.log(oBox);  // <div id="box">成都</div>
        </script>
    
  • 不占空间,隐藏显示时有transition效果
    .hidden {
        position: absolute;
        visibility: hidden;
    }
    
    <div class="div hidden">一杯敬朝阳 一杯敬月光</div>
    
  • 占空间,不能点击 visibility: hidden
    .vh {
        visibility: hidden;
    }
    
  • 不占空间,不能点击,键盘能访问 clip裁切
    .out {
        position: relative;
        left: -999em;
    }
    .clip {
        position: absolute;
        clip: rect(0, 0, 0, 0);
    }
    
    <div class="clip">
        <div class="out">青花瓷</div>
    </div>
    
  • 占空间,不能点击,键盘能访问 relative
    <div style="position: relative;top: -999em;">狮子座</div>
    
  • 占空间,可以点击 opacity
    <div style="opacity: 0; filter: alpha(opacity=0);">透明度</div>
    
  • 隐藏文字 使用text-indent
    <p style="text-indent: -999999px;">天下无双</p>
    

根据实际的隐藏场景选择合适的隐藏方法,这里就不再多说了,接着往下看吧

display与元素的显隐

我们都知道display如果值为none,则该元素以及所有后代元素都隐藏,反之如果值是非none的情况,则都为显示了

display可以说是web显隐交互中出场频率最高的一种隐藏方式,是真正意义上的隐藏,干净利落,不留痕迹

none做到了无法点击、无法使用屏幕阅读器等辅助设备访问,不占空间,其实不仅仅是这样,更应该知道的是

me: 我有酒,那么别说你没有故事

我知道display:none你才不是一个没有故事的女同学

display: none的元素的background-image图片根据不同浏览器的情况加载情况不一

  1. 在Firefox浏览器下,display:none的background-image图片不加载,包括父元素display:none也是如此

  2. 在Chrome和Safari浏览器,则根据父元素是否是否为none来影响图片加载情况,父元素带有display:none,图片不加载。

    父元素不带有display:none,而自身有背景图元素带的话,那也照样加载

  3. 在IE浏览器下,无论怎么搞都会请求图片资源,就是这么任性

因此,在实际开发的时候,例如头图轮播切换效果

那些默认需要隐藏的图片作为背景图藏在display:none元素的子元素上,这样的细小改动就可以明显提升页面的加载体验,也是非常实用的小技巧

whatever

上面说的兴致盎然,但实际中不可能全部都是背景图去加载图片资源的

还有另外一个好朋友,img元素,然并卵的是,上面说了一大堆加载不加载的情况,对img来说没个鸟用,人家不管你none不none的,依旧带着勇闯天涯的气概去请求着资源

活久见

都说display:none做事最纯粹,最干净,不能被点击,触碰到,然而下面这种情况又是什么鬼?

出来解释解释,我们都是文明人是绝对不会动武的!

<form action="/index.php">
    <input type="submit" id="hi" style="display: none;">
    <label for="hi">提交</label>
</form>

隐藏的按钮会触发click,触发表单提交,此现象出现在时髦的浏览器中(IE9+,现代标准浏览器中)

既然有这种例外情况那加了display:none的意义又是什么呢?

  • 意义在于:当按钮和label元素不在一个水平线上的时候,点击label元素不会触发锚点定位
  • But:作者不推荐这么做,因为submit按钮会丢失键盘可访问性

很多都是纯天然的

HTML中有很多标签和属性天然自带display:none

  • 标签:style, script, dialog
  • 属性:
    <input type="hidden" name="id" value="1" />
    // 专门用来放置类似token或id这些隐藏信息的
    // 所以说,表单元素的显隐并不影响数据的提交
    // 其真正影响的是disabled属性
    
  • HTML5中新增了hidden这个布尔属性,可以让元素天生隐藏起来
    <div hidden>看不见我</div>
    // IE11及现代标准浏览器都支持,如果做兼容需要这样写下即可
    [hidden] {
        display: none;
    }
    
  • 对于ol有序列表来说,如果子元素li有一项被设置了display:none,那么原本有10相的元素,最后总计数会被计算成9项,设置display:none的那项被后面的兄弟给取代了
  • 还有一点就是display:none其实并不会影响css3 animation动画的实现,而只是会影响transition过渡效果的执行,因此transition和visibility属性关系更好 (老铁扎心了)

既然说到了visibility了,那么就赶紧邀请visibility闪亮登场吧

visibility与元素的显隐

visibility要为自己正名,不仅仅是保留空间这么简单

看点多多:

  1. 继承性(最有意思的一个特点,不是我说的)
    • 父元素设置visibility:hidden,子元素也继承了该属性,也是看不见的
    • 不过本质区别在于,父元素设置了hidden后,子元素设置visible后,子元素是可以被看都的
    • 这点父元素设置了display:none,子元素就永远看不到了
    <ul style="visibility: hidden;">
        <li style="visibility: visible;">1</li>
        <li>2</li>
        <li>3</li>
        <li style="visibility: visible;">4</li>
    </ul>
    

2. 与css计数器

visibility:hidden虽然让元素不可见了,但是不影响其计数效果,不会重新计算结果

3. 与transition

设置了visibility:hidden的元素,可以很好的展现transition过渡效果

这是因为transition支持的css属性中有visibility(果然是兄弟),而并没有display属性

  1. 与JS

visibility:hidden除了对transition友好外,对js来说也很友好

在实际开发中,需要对隐藏元素进行尺寸和位置的获取,来实现布局精确定位的交互

此时,就建议使用visibility:hidden

.hidden {
    position: absolute;
    visibility: hidden;
}
let ele = document.getElementById('demo');

console.log('clientWidth: ' + ele.clientWidth);
console.log('clientHeight: ' + ele.clientHeight);
console.log('left: ' + ele.clientLeft);
console.log('top ' + ele.clientTop);
console.dir(ele.getBoundingClientRect());

好了以上内容要告一段落了,我们继续开始新的征程吧,哈哈

用户界面样式

用户界面样式指的是CSS世界中用来帮助用户进行界面交互的一些CSS样式,主要有outline和cursor等属性

和border形似的outline属性

outline表示元素的轮廓,语法也和border一样,分为宽度、类型和颜色三个值

.outline {
    height: 60px;
    width: 60px;
    outline: 2px dashed #0c9;
}

样式表示上相同,但是设计的初衷却是不太相同的,这一点天地日月可鉴

outline是一个和用户体验密切相关的属性,与focus状态以及键盘访问密切相关

对于按钮或链接,通常的键盘操作是:Tab键按次序不断focus控件元素(链接、按钮、输入框等表单元素),或者focus设置了tabindex的普通元素,然后按Shift+Tab是反向访问

重点来了

默认状态下,对于处于focus状态的元素,浏览器会通过发光or虚框的形式进行区分和提示,这是友好的用户体验,很有必要,不然用户很难知道自己当前聚焦在了哪个元素上面,会迷失自我

元素如果聚焦到了a链接上,按下回车键就会跳转到相应链接,以上的交互都是基于键盘访问的,这就是为什么outline和键盘访问如此亲密了

不专业的行为

很多时候直接在reset样式的时候,写成如下形式是非常不可取的

* { outline: 0 none; }
或
a { outline: 0 none; }

这样直接一竿子打死一群鸭子的做法是不对的,更多的时候是因为浏览器内置的focus效果和设计风格格格不入,才需要重置,而且要使用专门的类名

例如:
.input {
    outline: 0;
}
// 但是,必须把focus状态样式加上
.input:focus {
    border-color: Highlight
}

最后再强调一遍:万万不可在全局设置outline: 0 none;

这样的操作会造成键盘访问的时候用户找不到当前焦点,容易产生困扰的,为了大家好,收敛一下吧

下面来点干货: 在实际开发中,有时候需要让普通元素代替表单控件元素有outline效果

举个栗子:submit按钮来完成UI设计是非常麻烦的,所以使用label元素来移花接木,通过for属性和这些原生的表单控件相关联

[type="submit"] {
    position: absolute;
    clip: rect(0, 0, 0, 0);
}
.btn {
    display: inline-block;
    padding: 2px 12px;
    background-color: #19b955;
    color: #fff;
    font-size: 14px;
    cursor: pointer;
}
:focus + label.btn {
    outline: 1px dashed hotpink;
    outline: 3px auto -webkit-focus-ring-color;
}

<div class="panel">
    <input type="submit" id="box">
    <label for="box" class="btn">提交</label>
</div>

真正的不占据空间的outline及其应用

outline是一个真正意义上不占任何空间的属性,Amazing

头像剪裁的矩形镂空效果

先来看个效果图

上图就是矩形镂空效果,那么下面直接上代码,满满的干货

核心css是
.crop {
    overflow: hidden;
}
.crop .crop-area {
    width: 80px;
    height: 80px;
    outline: 256px solid #000;
    outline: 256px solid rgba(0, 0, 0, .5);
    background: url(about:blank);
    background: linear-gradient(to top, transparent, transparent);
    filter: alpha(opacity=50);
    cursor: move;
}
:root .crop-area {
    filter: none;
}

用一个大大的outline来实现周围半透明的黑色遮罩,因为outline无论设置多么多么大,都不会占据空间影响布局,至于超出的部分,直接给父元素设置一个overflow:hidden就搞定了 注意:

  • 因为考虑到IE8不支持rgba,所以上面借助了filter设置了透明度为一半效果
  • 但是由于IE9支持rgba,再借助:root来进行重置,不使用filter
  • 再加上IE10针对镂空元素会有点击穿透问题,所以再给background设置看不见的背景内容就可以解决

自动填满屏幕剩余空间的应用技巧

开发中很多时候,由于页面内容不够多,导致底部footer会出现尴尬的剩余空间,解决方法往往也有很多种,在此我们还是依然利用outline的功能来完美实现一下

关键的css就是设置一个超大轮廓范围的outline属性,如给个9999px,保证无论屏幕多高,轮廓颜色都能覆盖

值得注意的是,outline无法指定方位,它是直接向四周发散的,所以需要配合clip剪裁来进行处理,以左边和上边为边界进行裁剪

.footer {
    height: 50px;
}
.footer > p {
    position: absolute;
    left: 0;
    right: 0;
    text-align: center;
    padding: 15px 0;
    background-color: #00a1f5;
    outline: 9999px solid #00a1f5;
    color: #fff;
    clip: rect(0, 9999px, 9999px, 0);
}

<div class="footer">
    <p>没错,我就是footer</p>
</div>

光标属性

光标属性cursor我们真的是最熟悉的陌生人啊

为什么这么说呢,因为在众多的属性值面前,我们似乎只用到了pointer(手形)(最常用的,没有之一),move(移动),default(系统默认)这几样

在cursor的世界里,远比我们想象的要丰富很多,下面按照功能特性来对其进行分类吧

琳琅满目的cursor属性值

友情不友情的小提示:☆(表示常用)

  • 常规
    • cursor: auto; 默认值
      • 输入框表现是cursor: text (文本光标)
      • href属性的链接表现为cursor: pointer (手形光标)
      • button表现为cursor: default (默认箭头)
    • ☆ cursor: default; 系统默认光标
      • 误区产生的小故事:
        • 由于浏览器原生按钮样式兼容方面无法完善,尤其是IE盛行的年代,黑框、宽高不一致等问题层出不穷, 于是大家就使用a标签来模拟按钮,在每次hover上去的时候都会有一个手型效果,省去了额外添加, 所以久而久之就成了业内约定俗成的做法了
    • cursor: none; 这是让光标隐藏不见
      • what? 有何用?它的作用在看视屏的时候,全屏后鼠标静止不动3秒钟,就设置隐藏光标效果
      • IE8不支持,还要通过自定义光标来处理
      // 自定义光标
      .cur-none {
          cursor: url(transparent.cur), auto;
      }
      :root .cur-none {   // IE9+
          cursor: none
      }
      
  • 链接和状态
    • ☆ cursor: pointer; 手形
    • cursor: help; 帮助光标
      • 用在帮助链接或者提示信息的问号小图标上
      • 不过目前很少在网页上看到,更多的是使用cursor:pointer手形处理
    • cursor: progress; 进行中
      • 一个适用场景是网页加载js的情况,网络不好时,加载js时间过长
      body {
          cursor: progress;
      },
      // 当js加载完成后再将光标cursor设为auto;
      // 增加了用户体验
      document.addEventListener('DOMContentLoaded', () => {
          document.body.style.cursor = 'auto';
      });
      
    • cursor: wait;
      • 没用的光标,有个沙漏的样子
    • cursor: context-menu;
      • 上下文菜单,兼容性很复杂,汽油桶形状,用处不大
  • 选择
    • ☆ cursor: text; 文字可被选中
      • input默认光标表现就是cursor:text
        • 但是如果设置了disabled后,光标会自动变成cursor:default
      • 还有如果在现代浏览器中不允许文字选中的情况下,设置了user-select:none后,还要把对应的光标改变为cursor:default
      p {
          -webkit-user-select: none;
          -moz-user-select: none;
          -ms-user-select: none;
          cursor: default;
      }
      <p>弱水三千</p>
      // 不过现在最新版的浏览器都自动设置了cursor:default
      
    • cursor: vertical-text;
      • 垂直选中,文字排版是垂直情况的时候,基本没机会用到
    • cursor: crosshair;
      • 十字光标,它比较适合取色工具的场景中,平时用不到
    • cursor: cell;
      • 单元格光标,适合开发类似Excel表格的网页使用
      • 而且IE8还不支持,需要自定义,也是没机会表现了
  • 拖拽
    • ☆ ccursor: move;
      • 移动光标,表示当前元素是可移动的
      • 常用的弹窗组件给标题栏加上cursor:move,让用户知道是可以拖动的
    • cursor: copy;
      • 复制光标,表示当前元素可以复制,IE8不支持,需自定义,无实用
    • cursor: alias;
      • 别名光标,表示当前元素可以创建别名或快捷方式,同上copy一样,没个卵用
    • cursor: no-drop与cursor: not-allowed;
      • 样式相同,都表示禁止的
      • 值得注意的是:
        • 不要给禁用按钮加cursor: not-allowed
        • 因为它的状态只与拖拽行为相关
        • 所以禁用按钮光标还是用default更合适
  • 都是CSS3新增的光标类型
    • 缩放
      • cursor: zoom-in; 放大
      • cursor: zoom-out; 缩小
    • 抓取
      • cursor: grab; 五指张开的手
      • cursor: grabbing; 五指收起的手
      • Chrome下还需要加-webkit前缀生效
      • 这里QQ音乐PC端做了这样的cursor处理,如下图框选的位置
  • 自定义光标
    • 遇到一些IE8不支持的光标类型,可以通过自定义的手段来实现兼容
    • chrome等浏览器可以直接使用png图片作为光标
    • IE不行,它还是要用专门的.cur格式
    • 而自定义光标最大的作用其实是根据业务需求对光标进行样式上的自定义
    • 不过现在用的真是不多了

以上内容就介绍完了用户界面样式的全部内容了,还有最后一章的冷知识,大家不要方,继续看下去,了解一下,了解一下,了解一下

流向的改变

说出来你可能不信,direction可以改变水平流向,尽管知道或者使用过的人少之又少,但并不妨碍它的发光发热

而且属性简单好记,值少,兼容极好ie6支持,可以来挖掘一下它的神奇功效

direction

仅仅两个值:

  • direction: ltr; 默认值
    • ltr -> left-to-right(从左到右)
    • 东亚、欧美文字书写都是属于ltr模式的
  • direction: rtl;
    • rtl -> right-to-left(从右到左)
    • 阿拉伯语、希伯来语的书写属于rtl模式

当然看到这里你可能会感觉,这些说起来都没什么鸟用,因为大招是不轻易放出的,而真正有用的地方在于改变网页布局的时候

direction属性默认有一个特性

可以改变替换元素(img,input,textarea,select)或inline-block/inline-table元素的水平呈现顺序

举个栗子:颠倒顺序

<div class="box" dir="rtl">
    <p>我是第2名</p>
    <p>我是第一名</p>
</div>

<p dir="rtl">
    <img src="../1.jpg" alt="猫">
    <img src="../2.png" alt="狗">
</p>

再举个栗子:

比如制作弹窗组件的时候,确认取消按钮有的时候会根据用户的使用行为会显示在不同的位置

下面来看看这种特性的表现在实际开发中的作用

windows用户看到的样子:

mac用户看到的样子:

好了,direction的话题就告一段落,接下来介绍最后一个知识了,坚持住,快休息了

writing-mode

改变CSS世界纵横规则的writing-mode,如此强大的功能,居然没有被大家发掘和广发应用起来,实属遗憾了,话不多说,往下看

writing-mode作用及真正需要关注的属性值

writing-mode可以改变排版,变成垂直流,如下图所示

在使用语法上,也是需要记两套的,一套是IE私有属性,一套是CSS3规范属性

CSS3语法:

writing-mode: horizontal-tb;    默认值
    文本流是水平方向的
writing-mode: vertical-rl; 
    文本是垂直方向的,阅读顺序从右向左(古诗的顺序)
writing-mode: vertical-lr;
    文本垂直方向,阅读顺序从左到右(水平变成了垂直展示)

IE语法:

IE的writing-mode多达11个,真正有用的记住两个就好了

-ms-writing-mode: lr-tb;    初始值
    lr-tb对应的是CSS3语法中的horizontal-tb
-ms-writing-mode: tb-rl;
    tb-rl对应的是CSS3语法中的vertical-rl
-ms-writing-mode: tb-lr;
    tb-lr对应的是CSS3语法中的vertical-lr

针对实战版来整理一份writing-mode是这样的

writing-mode: lr-tb | tb-rl | tb-lr (IE8+)
writing-mode: horizontal-tb | vertical-rl | vertical-lr;

对于垂直排版来说,实际开发是很少会遇到的,不过还是要说说writing-mode带来的改变

水平方向也能margin合并

我们都知道两个相邻的元素垂直的margin会合并,当元素变为垂直流的时候,水平的margin也会合并

.vertical-mode {
    writing-mode: tb-rl;
    -webkit-writing-mode: vertical-rl;
    writing-mode: vertical-rl;
}

<div class="div vertical-mode">
    <div class="list" style="margin-left: 20px;">one</div>
    <div class="list" style="margin-right: 50px;">two</div>
</div>

普通块元素可以使用margin: auto实现垂直居中

img {
    display: block;
    margin: auto 0;
}

<div class="box vertical-mode">
    <img src="../1.jpg" alt="">
</div>
<div class="box vertical-mode" style="text-align: -center;background: gray;">
    <div class="demo">青花瓷</div>
    <!-- <img src="../2.png" alt=""> -->
</div>

上面分别是图片元素和普通块元素实现的垂直居中代码,眼见为实,看图

text-align:center实现图片垂直居中(同上实现的效果)

<div class="box vertical-mode" style="text-align: center;">
    <img src="../2.png" alt="">
</div>

使用text-indent实现文字下沉效果

核心css

.btn:active {
    text-indent: 2px;
}
<a href="javascript:;" class="btn vertical-mode">领</a>

这种文字下沉效果只能适合中文,因为在垂直流排版的时候中文是不会旋转的

而且这种效果只适合一个字的情景

实现全兼容的icon fonts图标旋转效果

老IE下让小图标旋转很麻烦,writing-mode把文档变成垂直流的时候,英文、数字和字符号都天然的转了90°

@font-face的兼容性很好IE5.5就支持了,所以就算是IE6IE7也没问题

<span class="icon-play vertical-mode">剪头朝下</span>

好了,这就是《CSS世界》里最后三章的全部内容了,终于写完了,哈哈,希望大家有收获一些冷知识,另外看书还是要买正版的,地址我就不发了,大家还请支持张鑫旭老师的作品

简单说两句

做个个人的小总结吧:

css有很多奇妙的地方,在某些特性当初被设计出来的时候可能只是为了某些图文排版而生

但是我们可以利用它们带来的特性发挥自己的创造力,实现其他很多意想不到的效果,因此,上面所讲述的所有知识点,尽管很多内容都有点奇技淫巧以悦妇孺的过程

但这也给我们开发的过程中,提供了一些很出奇的妙招,值得我们好好学习领悟

感谢个位的观看了,再见了,哈哈