css精进之道

503 阅读11分钟

position:sticky

当元素在屏幕内,表现为relative,就要滚出显示器屏幕的时候,表现为fixed.

  1. position:sticky要想生效,top属性或则left属性(看滚动方向)是必须要有明确的计算值的,否则fixed的表现不会出现。
  2. 父级元素不能有任何overflow:visible以外的overflow设置,否则没有粘滞效果
  3. 父级元素设置和粘性定位元素等高的固定的height高度值,或者高度计算值和粘性定位元素高度一样,也没有粘滞效果
  4. 同一个父容器中的sticky元素,如果定位值相等,则会重叠;如果属于不同父元素,且这些父元素正好紧密相连,则会鸠占鹊巢,挤开原来的元素,形成依次占位的效果
  5. sticky定位,不仅可以设置top,基于滚动容器上边缘定位;还可以设置bottom,也就是相对底部粘滞。如果是水平滚动,也可以设置left和right值。 sticky可以用于实现富有层次的滚动互动:
<article>
    <section>
        <h4>第一段标题</h4>
        <content>
            <p>12月2日,有网友爆料称...</p>
        </content>
        <footer>网友评论:...</footer>
    </section>
    <section>
        <h4>第二段标题</h4>
        <content>
            <p>...</p>
        </content>
        <footer>网友评论:...</footer>
    </section>
    ...
</article>

其中,标题和底部设置了sticky定位,如下:由于每一段短新闻都在section标签中,属于不同的父元素,因此,滚动的时候,后面的新闻标题才能把前面已经sticky定位的新闻标题推开,这是sticky定位天然的特性,无需任何JavaScript的帮助。

article h4, 
h4 {
    position: sticky;
    top: 0;
    z-index: 1;
}
content {
    position: relative;
}
footer {
    position: sticky;
    bottom: 50vh;
    z-index: -1;
}

效果中,网友评论从后面出现的效果:

  1. 定位用的bottom,效果和top正好是对立的。设置top粘滞的元素随着往下滚动,是先滚动后固定;而设置bottom粘滞的元素则是先固定,后滚动;
  2. z-index:-1让网友评论footer元素藏在了content的后面,于是才有了“犹抱琵琶半遮面”的效果。

Flex 基本概念

在 flex 容器中默认存在两条轴,水平主轴(main axis) 和垂直的交叉轴(cross axis),这是默认的设置,当然你可以通过修改使垂直方向变为主轴,水平方向变为交叉轴,在容器中的每个单元块被称之为 flex item,每个项目占据的主轴空间为 (main size), 占据的交叉轴的空间为 (cross size)。 这里需要强调,不能先入为主认为宽度就是 main size,高度就是 cross size,这个还要取决于你主轴的方向,如果你垂直方向是主轴,那么项目的高度就是 main size

.container {
    display: flex | inline-flex;       //可以有两种取值
}
/*分别生成一个块状或行内的 flex 容器盒子。简单说来,如果你使用块元素如 div,
/*你就可以使用 flex,而如果你使用行内元素,你可以使用 inline-flex。
需要注意的是:当时设置 flex 布局之后,子元素的 float、clear、vertical-align 的属性将会失效。
  1. flex-direction: 决定主轴的方向(即项目的排列方向)
.container {
    flex-direction: row | row-reverse | column | column-reverse;
}
/*row,主轴为水平方向,起点在左端 ...
  1. flex-wrap: 决定容器内项目是否可换行
  • 默认值:nowrap 不换行,即当主轴尺寸固定时,当空间不足时,项目尺寸会随之调整而并不会挤到下一行。
  • wrap:项目主轴总尺寸超出容器时换行,第一行在上方
  • wrap-reverse:换行,第一行在下方
  1. justify-content:定义了项目在主轴的对齐方式。
  • 默认值: flex-start 左对齐\ flex-end:右对齐
  • center:居中
  • space-between:两端对齐,项目之间的间隔相等,即剩余空间等分成间隙。
  • space-around:每个项目两侧的间隔相等,所以项目之间的间隔比项目与边缘的间隔大一倍。
  1. align-items: 定义了项目在交叉轴上的对齐方式
  • 默认值为 stretch 即如果项目未设置高度或者设为 auto,将占满整个容器的高度。
  • flex-start:交叉轴的起点对齐
  • flex-end:交叉轴的终点对齐
  • center:交叉轴的中点对齐
  • baseline: 项目的第一行文字的基线对齐

BFC

块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视化CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。

一个相对好懂得解释: BFC就是一个作用范围,可以把它理解成一个独立的容器。这个“独立”意味着作用范围和外界是毫不相关的。

BFC主要被用来解决以下常见的布局问题:

  • 清除浮动; 原理:BFC 这个区域的独立特性。因为独立,所以它要确保自己的作用范围不会对外界产生影响。把父元素创建为了一个BFC,那么父元素就要保证自己的子元素不会跑出去给别人添麻烦,所以会自动把自己的宽高适应到能囊括子元素的程度。
  • 阻止 margin 发生重叠; 把两个子元素放进两个不同的 BFC 里,利用 BFC “独立”的特性,可以使两个子元素的所有内容都被严严实实地包进各自的 BFC 中,避免与外界产生重叠的关系
  • 阻止元素被浮动的元素覆盖

创建BFC的方法(几种比较常见的):

  1. float的值不是none
  2. position的值不是static或者relative
  3. display的值是inline-block、table-cell、flex、table-caption或者inline-flex

CSS工程化

CSS 工程化是为了解决哪些方面的问题

  1. 宏观设计:CSS代码如何组织、如何拆分、模块结构怎样设计?
  2. 编码优化:怎样写出更好的 CSS?
  3. 构建:如何处理我的 CSS,才能让它的打包结果最优?
  4. 可维护性:代码写完了,如何最小化它后续的变更成本?如何确保任何一个同事都能轻松接手?

常见的工程化:

  • 预处理器:Less、 Sass 等; 类比js中的vue、react
  • 重要的工程化插件: PostCss; 类比js中的babel
  • Webpack loader 等 css-loader 和 style-loader

响应式布局

布局视口(layout viewport)与视觉视口(visual viewport)

  1. 视觉视口,它指的是你的设备实际的可见区域,也就是浏览器的宽高。在PC端,浏览器的宽高我们可以任意缩放;但在移动端,浏览器的宽高一般是不支持改变的,其大小由设备屏幕的大小决定

    通过访问 window.innerWidth 和 window.innerHeight 两个属性,我们可以获取到视觉视口的宽高

  2. 布局视口指的是页面实际布局所占用的区域,我们可以通过 document.documentElement.clientWidth 来获取布局视口的宽度。

  3. 理想视口(ideal viewport)

    “理想的尺寸”指的是整个页面刚好全部覆盖手机屏幕的尺寸。这个尺寸不需要我们手动计算,厂商根据手机屏幕尺寸大小,会提供一个最符合这个屏幕尺寸页面设计方案,我们通过这样一行代码就可以应用这个方案:

<meta name="viewport" content="width=device-width">
此处 width 属性对应的就是布局视口的值。设置 width = device-width 的目的,正是为了使布局视口的宽度刚好匹配上视觉视口的宽度。

rem 和 em

rem 指的是相对于HTML根元素的字体大小(font-size)来计算的长度单位。比如说我给 html 元素设置一个 font-size 是 100px,那么1rem = 100px

em 也是一个相对长度单位,它相对的是使用他们的元素的字体大小。

不管元素本身有没有显式地设置 font-size,em 取的都是当前元素的 font-size。

响应式布局方案

  1. 媒体查询

既然要解决的是屏幕大小不确定的问题,那么最直接的思路就是想办法去感知屏幕大小的变化,并根据不同的屏幕大小展示不同的样式。媒体查询做的就是这件事情,它是一个古老而经典的响应式布局解决方案,是 BootStrap 响应式特性的基石。

@media screen and (max-width: 320px) {
    div {
     width: 160px;
    }
}

@media screen and (min-width: 768px) {
    div {
     width: 300px;
    }
}
@media 是媒体查询属性的标识,“screen”指的是媒体类型。max-width:对最大宽度的限制。min-width:对最小宽度的限制
  1. rem

rem 是一个以根元素 font-size 大小为基准的相对单位。如果我们以 rem 作为布局单位,那么只要根元素大小发生了改变,就有“牵一发而动全身”的效果,整个页面中所有相关元素的大小都会跟着进行相应的放缩。如果我们能够根据设备屏幕大小的不同,动态地修改根元素的 font-size,那么就相当于间接地修改了页面中所有元素的大小,进而实现了响应式布局。

function refreshRem() {
    // 获取文档对象(根元素)
    const docEl = doc.documentElement;
    // 获取视图容器宽度
    const docWidth = docEl.getBoundingClientRect().width;
    // rem 取值为视图容器宽度的十分之一大小
    const rem = width / 10;
    // 设置 rem 大小
    docEl.style.fontSize = rem + 'px';
}
// 监听浏览器窗口大小的变化
window.addEventListener('resize', refreshRem);
  1. vw/vh

vw 和 vh 是一种区别与 rem 和 px 的 css 尺寸单位。它们天生自带等比缩放能力:1vw = 视觉视口宽度 / 100;1vh = 视觉视口高度 / 100 4. 取舍

  • 这三种方案之间不是互斥的关系。在实践中,我们会经常遇到 rem+媒体查询、vw/vh+媒体查询这样的应用场景
  • rem 和 vw/vh 之间不存在绝对的优劣,在选型上需要注意的是兼容性:vw/vh 的兼容性不如 rem。早年 rem 一直是响应式布局的主流解决方案,最关键的原因就是兼容性好,不挑食。而 vw/vh 则需要ios8、安卓4.4及以上操作系统的支持。话虽如此,2020年了,低于 ios8 和安卓 4.4 的机型在市场中的占比并不高

###高清方案

1px 的 bug 就这样轻松搞定了,但这样做的副作用也很大,整个页面被缩放了。这时候我们的 1px 已经被处理成物理像素大小了,这样的大小在手机上显示边框很合适。但仔细想想,一些原本不需要被缩小的内容,比如文字、图片等,也被无差别缩小掉了。

没错,页面上的图片和文字都被缩小了 dpr 倍,现在我们需要把原来写的 css 像素都再乘以 dpr 倍。这样才能既解决 1px 问题,又与原来大小保持一致。

再来看公式:viewport-width = screen.width * dpr ,dpr = 设备物理像素 / screen.width, 因此设置viewport = 设备物理像素 即可达到目的,如果视觉稿一开始就以设备物理像素来给出,那么我们就不用再乘以 dpr 倍了,直接设计稿里 px 多少,css 里 px 就写多少即可。

那如果设计稿和设备物理像素不一样怎么办?

比如设计稿是 750 的,手机 screen.width = 375 dpr = 3,按照上面的公式,viewport-width = 1125,那么按照设计稿来写 px,虽然高清了但肯定是铺不满的,还需要再适配一下。

这个适配问题就可以用 rem 来解决。我们把视觉稿总的 fontSize 记为 baseFontSize,然后将 baseFontSize 记为rem,这样一来 1px=0.01rem(因为 1rem = 100px),最后针对不同手机屏幕尺寸和dpr动态改变根节点html的 font-size 大小即可。

rem = _baseFontSize / _psdWidth * docEl.clientWidth; 在这个公式里,假如视觉规范是 750(_psdWidth = 750),那么我们就确保了 rem 无论在任何页面里,都一定是占据了这个页面的 100/750 这个比例,也就是说 1px = 0.01rem 永远占据这个页面的 1/750,如此便能够实现不同宽度机型的适配啦。

读到这里,大家会发现 rem 相对于 vw/vh 的一个非常重要的优势:灵活。对于 viewport 解决 1px 问题、高清方案适配这样的场景, vw/vh 是束手无策的。这又为我们的布局单位选型提供了一个新的依据。