虽然能使用CSS的多列布局、Flexbox布局和Grid布局等模拟出瀑布流布局效果,但更多的同学还是更喜欢使用一些JavaScript库来实现瀑布流布局,比如 Masoonry。
为了能让原生的CSS直接实现瀑布流布局效果,早在2017年社区中就有人提出用原生的CSS实现瀑布流布局效果,不幸的是,直到现在也还只是一个实验性的属性,而且仅在Firefox Nightly浏览器中支持。
.masonry {
display: grid;
gap: 20px;
grid: masonry / repeat(auto-fill, minmax(250px, 1fr));
}
比如这个Demo[12]。
为了能在Firefox Nightly浏览器能正常的查看上面Demo的效果,你需要确保开启了相应的功能。如果没有的话,请在Firefox Nightly浏览器地址栏中输入 about:config,然后搜索 layout.css.grid-template-masonry-value.enabled,并将其设置为true:
然后重启浏览器,查看Demo,你看到的效果将会是像下面这样:
▐ gap
“Gap”从字面上来解释的话可以有“间隙,间隔”之意。那么在Web的布局中总是避免不了处理块与块以及行与行之间的间距。
而在CSS的世界中,用来控制元素之间的间距的间距,一般会使用盒模型中的外距,即 margin 属性,但是往往很多时候,使用margin来控制元素之间间距并不能很好的满足设计师的诉求。比如说,元素只和元素之间有间距,但和它的父容器之间没有任何的间距。针对于这样的场景,使用gap属性会比使用margin要容易控制的多。
注意,上图来自于《Next-generation web styling》[13]一文。
CSS的 gap 属性自身最大的特点就是:gap 是相对于流的,这意味着它会根据内容流的方向动态变化。比如说书写模式的改变,gap 也会自动改变。
早期在CSS中,gap 分很多种,在不同的容器格式中,叫法不同,比如在多列布局(Multi-column Containers)中对应的是column-gap:
body {
column-gap: 35px;
}
但在网格容器(Grid Containers)又被称为 grid-row-gap 和 grid-column-gap。
除此之外,它还可以被运用于Flexbox容器(Flexbox Containers),只不过早前,在Flexbox中没有类似 flex-row-gap 和 flex-column-gap 这样的属性。
需要注意的是,在Flexbox模块中是没有gap属性,但这并不影响我们在Flexbox布局中使用gap属性,这是因为gap统一纳入到了 CSS Box Alignment Module Level 3模块。而且gap是row-gap和column-gap的简写属性:
我们现在可以在多列布局,Flexbox布局和网格布局中像下面这样使用 gap:
// 多列布局.multi__column { gap: 5ch}
// Flexbox布局.flexbox { display: flex; gap: 20px}
// Grid布局.grid { display: grid; gap: 10vh 20%}
从上面示例代码中我们可以发现,gap 是 row-gap 和 column-gap 的简写属性,而且 gap 可以接受一个值也可以接受两个值,当 gap 只有一个值时,表示 row-gap 和 column-gap 的值相同;当 gap 有两个值时,其中第一个值是 row-gap,第二个值是 column-gap。
.gap {
gap: 10px;
}
// 等同于
.gap {
row-gap: 10px;
column-gap: 10px
}
.gap {
gap: 20px 30px;
}
// 等同于
.gap {
row-gap: 20px;
column-gap: 30px;
}
特别声明一点,虽然CSS新增了gap属性(row-gap、column-gap),但Grid中早期的grid-row-gap和grid-column-gap属性同样可用。
▐ aspect-ratio
aspect-ratio 是 CSS Box Sizing Module Level 4 模块中的一个用来计算元素盒子宽高比的属性。在这个属性还没有之前,在CSS中都是通过其他一些方法来模拟宽高比的效果。比如:
.aspectration {
position: relative;/因为容器所有子元素需要绝对定位/
height: 0; /容器高度是由padding来控制,盒模型原理告诉你一切/
width: 100%;
}
.aspectration[data-ratio=“16:9”] {
padding-top: 56.25%;
}
.aspectration[data-ratio=“4:3”]{
padding-top: 75%;
}
如果浏览器支持了aspect-ratio的话,可以像下面这样使用:
div { aspect-ratio: 1 / 1;}
比如@rachelandrew在Codepen提供的一个示例[14],我在该示例的基础上稍作调整了一下:
▐ :target 和 :target-within
:target和:target-within都是 Selectors Level 4 模块中的两个伪元素。可能很多同学对:target更熟悉一些,甚至用:target伪元素的特性制作了 Tab 、Accordion 和 Modal 等UI交互效果。
比如下面这个手风琴的效果就是用:target伪元素制作的:
这里简单的来看看:target和:target-within的作用。
在某些文档语言中,文档的URL可以通过URL的片段进一步指向文档中的特定元素。以这种方式指向的元素是文档的目标元素。其中片段标识符是URL中紧跟#的部分,例如#top或#fontnote1。你可能已经使用它们创建页面内导航,比如大家常见的“跳转链接”。有了:target伪类,我们可以突出显示与该片段对应的文档部分,而且无需JavaScript也可以做到这一点。
比如下面这个简单的示例:
Table of Contents
- Jump to the first paragraph!
- Jump to the second paragraph!
- This link goes nowhere, because the target doesn't exist.
My Fun Article
You can target this paragraph using a URL fragment. Click on the link above to try out!
This is another paragraph, also accessible from the links above. Isn't that delightful?
/* CSS */
p:target {
background-color: gold;
}
/* 在目标元素中增加一个伪元素*/
p:target::before {
font: 70% sans-serif;
content: “►”;
color: limegreen;
margin-right: .25em;
}
/在目标元素中使用italic样式/
p:target i {
color: red;
}
你可以看到像下图的效果:
而:target-within伪类应用于:target伪类所应用的元素,以及在平面树(Flat Tree)的后代(包括非元素节点,比如文本节点)与匹配:target-within的条件相匹配的元素。
article:target-within {
background-color: hsl(var(–surfaceHSL) / 10%);
}
其实在选择器Level 4模块中还新增了很多其他的伪类选择器,如果你对这方面新增的选择器感兴趣的话,可以听一听@Adam Argyle和@Ana Tudor一起办的CSS Podcast,其中第十四期[15]就是专门聊CSS的伪类选择器的。
▐ CSS逻辑属性
如果你接触过CSS书写模式特性,你会发现以前我们熟悉的物理属性在不同的语言环境之下很难满足布局的需求,比如英语和阿拉伯语,日语和蒙语等,我们设置的margin-left有可能不是margin-left,width也有可能不是width。
这个时候,CSS逻辑属性就显得尤其重要。换句话说,逻辑属性的出现,我们以往熟悉的盒模型也将带来很大的变化:
下图是我们熟悉的物理属性和逻辑属性的对应关应:
对于块轴(block axis)和内联轴(inline axis)区别,同样用一张图来描述这两者吧:
块轴和内联轴和CSS的书写模式writing-mode以及direction和HTML的dir有关系。换句话说:
-
块轴:主要定义网站文档(元素块)流,CSS的书写模式writing-mode会影响块轴的方向。
-
内联轴:主要定义网站的文本流方向,也就是文本的阅读方式,CSS的direction或HTML的dir会影响内联轴的方向。
▐ min()、max()和clamp()
min()、max()和clamp()三个函数称为“比较函数”。早在《聊聊min(),max()和clamp()函数》一文中对其做过详细的介绍。这里不做详细介绍,仅和三张图来分别展示他们的功能。
我们可以使用 min()设置最大值:
max()和min()相反,返回的是最大值。使用max()设置一个最小值:
clamp()函数和min()以及max()不同,它返回的是一个区间值。clamp()函数接受三个参数,即 clamp(MIN, VAL, MAX),其中MIN表示最小值,VAL表示首选值,MAX表示最大值。它们之间:
-
如果VAL在MIN和MAX之间,则使用VAL作为函数的返回值;
-
如果VAL大于MAX,则使用MAX作为函数的返回值;
-
如果VAL小于MIN,则使用MIN作为函数的返回值。
这里有一个关于clamp() 的示例,尝试着拖动浏览器视窗的大小,你可以看到类似下图这样的效果:
我们再来看几个和文本相关的特性:
▐ leading-trim 和 text-edge
一直以来,在Web的排版中行高(line-height)总是令Web开发者感到困惑和头痛,主要是因为line-height在CSS中是一个非常复杂的体系。他的计算总是会涉及到很多因素:
@iamvdo的《Deep dive CSS: font metrics, line-height and vertical-align》一文对这方面做过深入的阐述!
在还原UI时,文本的行高总是让我们计算元素块之间的间距带来一定的麻烦:
为了解决这方面的烦恼, CSS Inline Layout Module Level 3新增了一个leading-trim和text-edge属性。可以让我们删除每一种字体中的额外间距,以便我们可以更好的计算相邻块元素之间的间距。
h1 {
leading-trim: both;
text-edge: cap alphabetic;
}
上面的示例首先使用text-edge来告诉浏览器想要的文本边缘是cap高度和字母基线(alphabetic baseline)。然后用leading-trim对文本两边进行修剪。
注意,leading-trim只影响文本框,它不会切断其中的文字。
示例中的两行简单的CSS创建了一个包含文本的干净的文本框(不受line-height相关的特性影响)。这有助于实现更精确的间距,并创建更好的视觉层次结构。
CSS的text-edge和leading-trim分别可接受的值:
text-edge: leading | [ text | cap | ex | ideographic | ideographic-ink ] [ text | alphabetic | ideographic | ideographic-ink ]?
leading-trim: normal | start | end | both
如果你对leading-trim特性感兴趣的话,除了阅读规范之外,还可以阅读下面几篇文章:
-
The Thing With Leading in CSS
-
Leading-Trim: The Future of Digital Typesetting
-
Rethinking line-sizing and leading-trim
▐ ::grammar-error 和 ::spelling-error
::grammar-error和::spelling-error是两个非常有意思的伪元素选择器。从字面说我们可以知道, Grammar error 指的是语法错误, Spelling error指的是拼写错误。其实这两种现象在我们平时书写文本的时候经常可见,可能会由于手误, 将某个单词或标点符号用错,甚至语法上的错误。针对于这种现象,我们总是希望有一定的提示信息来提示我们,比如颜色上的差异,添加一些下划线等等:
在 CSS Pseudo-Elements Module Level 4 的高亮伪元素中我们可以看到这两个伪元素的身影:
-
::grammar-error:浏览器为语法错误的文本段添加样式。
-
::spelling-error:浏览器为拼写错误的文本段添加样式。
在CSS中并不是所有属性都能运用于这两个伪元素,到目前为止,只有color、background-color、cursor、text-emphasis-color、text-shadow、outline、text-decoration、fill-color、stroke-color 和stroke-width可以用于这两个伪元素。
:root::spelling-error {
text-decoration: spelling-error;
}
:root::grammar-error {
text-decoration: grammar-error;
}
[spellcheck]::spelling-error {
text-decoration: wavy underline var(–neon-red);
}
[grammarcheck]::grammar-error {
text-decoration: wavy underline var(–neon-blue);
}
▐ 新增相对单位:cap、lh、rlh、vi和vb
CSS中单位和值中,单位有:
但在相对单位中并没有提到cap、lh、rlh、vi和vb这几个相对单位。
从上表的描述来看,其中cap、lh、rlh的计算都和元素的字体以及行高等有关系。我用下图来描述一个字体的Cap Height,Line Height等:
三、Web性能
▐ contain 和 content-visibility
这两个属性是属于 CSS容器模块 的,其最大的特点应该是可以帮助Web开发者提高Web页面的性能:
当容器的内容发生变化时,浏览器考虑到其他元素可能也会发生变化,于是就会去检查页面中所有的元素。一直以来浏览器都是这么做的,大家都习以为常了。但从另一方面来说,开发者很清楚当前修改的元素是否独立、是否影响其他元素。因此如果开发者能把这个信息通过CSS告诉浏览器,那么浏览器就不需要再去考虑其他元素了,这就是非常完美的事情。而CSS容器模块中的contain属性就为我们提供了这种能力。
@Manuel Rego Casasnovas在《An introduction to CSS Containment》文章中提供的一个示例:
假设一个页面有很多个元素,在这个示例中,我们有10000个这样的元素:
Lorem ipsum...使用JavaScript的textContent这个API来动态更改div.item > div的内容:
const NUM_ITEMS = 10000;
const NUM_REPETITIONS = 10;
function log(text) {
let log = document.getElementById(“log”);
log.textContent += text;
}
function changeTargetContent() {
log(“Change “targetInner” content…”);
// Force layout.
document.body.offsetLeft;
let start = window.performance.now();
let targetInner = document.getElementById(“targetInner”);
targetInner.textContent = targetInner.textContent == “Hello World!” ? “BYE” : “Hello World!”;
// Force layout.
document.body.offsetLeft;
let end = window.performance.now();
let time = window.performance.now() - start; log(" Time (ms): " + time + “\n”);
return time;
}
function setup() {
for (let i = 0; i < NUM_ITEMS; i++) {
let item = document.createElement(“div”);
item.classList.add(“item”);
let inner = document.createElement(“div”);
inner.style.backgroundColor = “#” + Math.random().toString(16).slice(-6);
inner.textContent = “Lorem ipsum…”;
item.appendChild(inner);
wrapper.appendChild(item);
}
}
如果不使用contain,即使更改是在单个元素上,浏览器在布局上的渲染也会花费大量的时间,因为它会遍历整个DOM树(在本例中,DOM树很大,因为它有10000个DOM元素):
在本例中,div的大小是固定的,我们在内部div中更改的内容不会溢出它。因此,我们可以将contain: strict应用到项目上,这样当项目内部发生变化时,浏览器就不需要访问其他节点,它可以停止检查该元素上的内容,并避免到外部去。
CSS容器模块中的content-visibility属性会显著影响第一次下载和第一次渲染的速度。此外,你可以立即与新渲染的内容交互,而无需等待内容的其余部分加载。该属性强制用户代理跳过不在屏幕上的标记和绘制元素。实际上,它的工作方式类似于延迟加载,只是不加载资源,而是渲染资源。
简单地说,CSS的content-visibility属性 可跳过不在屏幕上的内容渲染,包括布局(Layout)和渲染(Paint),直到真正需要布局渲染的时候为止。所以利用它可以使用初始用户加载速度更快,还能与屏幕上的内容进行更快的交互。
上图来自于@Una Kravets和@Vladimir Levin的《content-visibility: the new CSS property that boosts your rendering performance》一文。从图中我们可以获知,使用content-visibility: auto属性可使分块的内容区域的初始加载性能提高7倍。
有关于这方面的介绍,还可以阅读:
-
CSS Containment in Chrome 52
-
Helping Browsers Optimize With The CSS Contain Property
-
An introduction to CSS Containment
-
Let’s Take a Deep Dive Into the CSS Contain Property
-
CSS Containment
-
content-visibility: the new CSS property that boosts your rendering performance
-
Short note on content-visibility: hidden
-
Using content-visibility: hidden
-
Using content-visibility: auto
▐ 数据服务
数据服务指的是 Data Saver。啥意思呢?不做解释,直接用一段代码来描述:
@media (prefers-reduced-data: reduce) {
header {
background-image: url(/grunge.avif);
}
}
我想大家对于@media (prefers-reduced-data: reduce)应该不会陌生吧。是的,它就是我们所说的CSS媒体查询。只不过稍有不同的是,这个媒体查询是根据用户在设备上的设置喜好来做条件判断。比如上面示例代码,当用户在设备上开启了“Low Data Mode”(低数据模式),会加载grunge.avif图像,可以帮助iPhone上的应用程序减少网络数据的使用:
到目前为止,CSS媒体查询提供了多个媒体特性,可以以用户在设备上的喜好设置做为判断,比如iOS13+开始,iPhone提供的DarkMode模式(prefers-color-scheme):
比如,使用prefers-reduced-motion媒体查询用于检测用户的系统是否被开启了动画减弱功能:
上面提到的这些媒体查询条件都是在 CSS Media Queries Level 5 模块中新增的。
除了上面提到的之外,还有一些我们平时很少见的媒体查询条件,比如:
@media (hover: hoveer) {}
@media (hover: none) and (pointer: coarse) {}
@media (hover: none) and (pointer: fine) {}
@media print and (min-resolution: 300dpi) {}
@media (scan: interlace) {}
@media (update) {}
@media(environment-blending: additive){}
@media (color) {}
变量字体
变量字体是一个非常有意思的CSS特性,它也常被称为“可变字体”,先给大家展示一个Demo[16]:
变量字体的目标是让网站性能更好,同时给用户提供了更多选择和扩展。变量字体是类似矢量图形,允许为各种字体轴定义不同的值。变量字体设计中一般有五个注册轴,包括字体、字宽、斜体和光学尺寸。每个注册轴都有一个对应的四个字母的标记,可以映射到现有的CSS属性:
除了注册轴之外,字体设计器还可以包含自定义轴。自定义轴让可变字体变得更具创造性,因为不限制自定义轴的范围、定义或数量。与注册轴类似,自定义轴具有相应的四个字母标记。但是,自定义轴的字母标记必须是大写的。例如,你定义了一个注册轴是grade,其对应的字母标记是 GRAD。
比如上面示例效果对应的代码:
.text {
font-weight: 800;
font-style: italic;
font-variation-settings: “SSTR” 183, “INLN” 648, “TSHR” 460, “TRSB” 312, “TWRM” 638, “SINL” 557, “TOIL” 333, “TINL” 526, “WORM” 523;
transition: font-variation-settings .28s ease;
}
.text:hover {
font-weight: 400;
font-style: normal;
font-variation-settings: “SSTR” 283, “INLN” 248, “TSHR” 160, “TRSB” 112, “TWRM” 338, “SINL” 257, “TOIL” 133, “TINL” 426, “WORM” 223;
}
在Firefox浏览器中,我们还可以通过开发者工具中“字体”选项提供的相关可变字体注册轴的值调整:
调整完之后,可以获得新代码:
p {
font-size: 60px;
line-height: 37px;
letter-spacing: 0.113em;
font-variation-settings: “SSTR” 450, “INLN” 741, “TSHR” 292, “TRSB” 497, “TWRM” 173, “SINL” 557, “TOIL” 728, “TINL” 526, “WORM” 523, “TFLR” 362, “TRND” 516, “SWRM” 536, “TSLB” 509;
font-weight: 491;
}
对应效果如下:
Web可访问性
▐ :focus-visible 和 :focus-within
一直以来我很容易把:focus-within和:focus-visible混淆。其实:focus-within和:focus-visible都是CSS选择器 Level 4中用户操作类伪类选择器。早前在《初探CSS 选择器Level 4》中聊过:focus-within,但没有聊过:focus-visible。
另外,在《CSS :focus-within》教程中就提到过, :focus-within能非常方便处理获取焦点状态。当元素本身或其后代元素获得焦点时,:focus-within伪类的元素就会有效 。:focus-within伪类选择器的行为本质上是一种父选择器行为,子元素的状态会影响父元素的样式。由于这种“父选择器”行为需要借助用户的行为触发,属于“后渲染”,不会与现有的渲染机制相互冲突。
如果上面的介绍让你感到困惑的话,可以看下面这个Demo[17]。你会发现,当的后代元素得到焦点时,会有一个放大的效果:
实现上图的效果代码非常的简单:
form:focus-within {
box-shadow: 0px 0.2em 2.5em #c4c4c4;
transform: scale(1.025);
}
对于:focus-visible伪类来说,当元素匹配:focus伪类并且客户端(UA)的启发式引擎决定焦点应当可见时就会生效。这个选择器可以有效地根据用户的输入方式(鼠标 vs 键盘)展示不同形式的焦点。
简单点说,按键盘tab键和鼠标点击得到的焦点效果不同。比如:
/* 链接得到焦点时的样式 */
a:focus {
}
/*
-
- 如果链接有焦点,但是浏览器通常不会显示默认的焦点样式,会覆盖上面的焦点样式
-
- 不是按键盘
tab
键让链接得到的焦点,比如说鼠标点击链接
- 不是按键盘
*/
a:focus:not(:focus-visible) {
}
/* 按键盘tab键让链接得到焦点的样式 */
a:focus-visible {
}
来看一个具体的案例。这个示例中分别用鼠标点击链链和按键盘tab键让链接得到焦点,它的样式是不一样的:
五、Web美化
▐ Color Level 4 和 Level 5
CSS Color Level 4 和 Level 5 两个模块主要是为我们推出了一些颜色使用的新属性,比如:
-
<hwb()> :HWB(白色-白色-黑色的缩写)是另一种指定颜色的方法,类似于HSL,它描述了一开始的色调,然后是一定程度的白色和黑色混合到基本色调
-
<lab()>和<lch()> :Lab是由一个亮度通道和两个颜色通道组成的。在Lab颜色空间中,每个颜色用L(亮度)、a(从绿色到红色的分量)和b(从蓝色到黄色的分量)三个数字表示。而Lch分别表示了颜色的亮度、饱和度和色调
-
<gray()> :灰色是完全去饱和的颜色,gray()函数表示法简化了对这组常见颜色的指定,因此只需要一个数值参数,用来指定颜色的灰度
-
<color()> :该函数允许在特定的颜色空间中指定颜色
-
<device-cmyk()> :该函数是以CMYK(青色、品红、黄色和黑色)组合,在该设备上生成特定的颜色
-
:根据用户操作系统来匹配颜色
-
color-mix() :该函数接受两个规范,并在给定的颜色空间中以指定的数量返回它们混合的结果
-
color-contrast() :该函数首先使用一种颜色(通常是背景色),然后使用两种或两种以上颜色的列表,它从该列表中选择亮度对比度最高的颜色到单一颜色
-
color-adjust() :该函数接受一个规范,并通过指定的转换函数在给定的颜色空间中返回调整该颜色的结果 颜色扩展:根据现有的颜色(在这称为“原始颜色”)在函数的目标颜色空间中生成颜色,它是<rgb()>、<rgba()>、<hsl()>、<hsla()>、<hwb()>、<lab()>和<lch()>的扩展颜色
对于Web开发者来说,最大的感受是语法规则有较大的变化:
来看两个示例:
// Color Level 4
.colour {
–fn-notation: hsl(2rad 50% 50% / 80%);
–neon-pink: color(display-p3 1 0 1);
–gray: lch(50% 0 0);
–fallback: color(lab 25 25 25, display-p3 1 0 1, #ccc);
}
// Color Level 5
.colour {
–pink: color-mix(red, white);
–halfpink: color(var(–pink) / 50%);
–halfred: rgb(from #f00 / 50%);
–darkred: hsl(from red h s calc(l * .25));
}
这里再特意提一下display-p3颜色,我们可以配合CSS的媒体查询@media (dynamic-range: high)一起使用:
@media (dynamic-range: high) {
.neon-red {
–neon-glow: color(display-p3 1 0 0);
}
.neon-pink {
–neon-glow: color(display-p3 1 0 1);
}
.neon-purple {
–neon-glow: color(display-p3 0 0 1);
}
.neon-blue {
–neon-glow: color(display-p3 0 1 1);
}
.neon-green {
–neon-glow: color(display-p3 0 1 0);
}
.neon-yellow {
–neon-glow: color(display-p3 1 1 0);
}
.neon-white {
–neon-glow: color(display-p3 1 1 1);
}
}
注意,Display-P3颜色空间颜色要比sRGB颜色空间中的颜色更鲜艳:
也可以说,Display-P3是sRGB的一个超集,大约要大35%:
Safari 97预览版本可以查看到display-p3的效果:
同样的,在color()函数中使用display-p3指定颜色空间时,也可以和sRGB颜色空间相互转换,如下图所示:
下面是@Adam Argyle 在Codepen提供的一个有关于display-p3的示例[18]:
▐ ::marker
::marker也是CSS的伪元素,现在被纳入到CSS Lists Module Level 3规范中。在该规范中涵盖了列表和计算数器相关的属性,比如我们熟悉的list-style-type、list-style-position、list-style、list-item、counter-increment、counter-reset、counter()和counters()等属性。
在CSS中display设置list-item值之后就会生成一个Markers标记以及控制标记位置和样式的几个属性,而且还定义了计数器(计数器是一种特殊的数值对象),而且该计数器通常用于生成标记(Markers)的默认内容。
一时之间,估计大家对于Markers标记并不熟悉,但对于一个列表所涉及到的相关属性应该较为熟悉,对于一个CSS List,它可以涵盖了下图所涉及到的相关属性:
事实上,CSS的::marker和伪元素::before(或::after)类似,也可以通过content和attr()一起来控制Marker标记的效果。需要记住,生成个性化Marker标记内容需要做到几下几点:
-
非列表项li元素需要显式的设置display:list-item (内联列表项需要使用display: inline list-item)。
-
需要显式设置list-style-type为none。
-
使用content添加内容(也可以通过attr()配合data-*来添加内容)。
比如下面这个小示例:
另外,::marker还没有得到浏览器支持之前,一般都是使用CSS的计数器来实现一些带有个性化的有顺序列表,比如下面这样的效果:
是不是很有意思,有关于::marker伪元素更详细的介绍,还可以阅读:《 Custom bullets with CSS ::marker》一文。
▐ text-emphasis
先上张图:
上图的效果就是使用CSS的text-emphasis实现的。在以往我们要给文本添加一些装饰效果,除了加粗(font-weight)、倾斜(font-style)、阴影(text-shadow),文本上面或下面添加线条(text-decoration)等之外也没有别的了(当然,还可以使用其他的CSS实现一些特殊效果)。但要实现上图的效果还是有一定难度的。不过text-emphasis的出现,这一切变得要简单地多。
text-emphasis是属于 CSS Text Decoration Module 规范中的一个特性,在 Level 3中和text-emphasis有关的属性还有text-emphasis-style和text-emphasis-color,而且text-emphasis是这两个属性的简写属性。另外还有一个用来指定标记符位置的属性text-emphasis-position:
.emphasis {
text-emphasis: triangle rebeccapurple;
text-emphasis-position: under;
}
在 Level 4的规范中还新增了text-emphasis-skip属性。
具体的效果如下:
▐ color-scheme
color-scheme属性来自于 CSS Color Adjustment Module Level 1。如果你在自己的项目中实现过iOS的DarkMode的效果,你肯定使用过CSS的媒体查询prefers-color-scheme。
:root {
–color: #fff;
–color-bg: #000;
}
@media (prefers-color-scheme: dark) {
–color: #000;
–color-bg: #fff;
}
body {
color: var(–color);
background-color: var(–color-bg)
}
虽然说,这可以让用户根据自己喜好来选择自己喜欢的皮肤,但这并不能覆盖所有的。这个时候可以使用color-scheme属性来做一定的补充。该属性允许用户通过用户代理控制自动调整色彩模式,比如暗色模式,对比度调整或特定所需的配色方案。这些值与用户的首选项进行协商,从而产生影响用户界面(UI)内容的所选颜色方案,例如表单控制和滚动条的默认颜色,以及CSS系统颜色的使用值。
color-scheme有两种用法,先来看第一种:
:root {
color-scheme: dark light;
}
在:root元素上,使用color-scheme颜色方案进行渲染,会影响画布的表面颜色(即全局背景颜色),color属性的初始值和系统颜色的使用值,还应该影响视窗滚动条颜色。
另外一种使用方式是在标签上:
要遵守color-scheme CSS属性,需要先下载CSS(如果它是通过引用的)并进行解析。为了帮助用户代理立即用所需的颜色方案渲染页面背景,还可以在元素中提供一个颜色方案值。
由于meta标记和CSS属性(如果应用到:root)最终都会导致相同的行为,所以我更建议通过meta标记指定颜色方案,这样浏览器可以更快地采用首选方案。
最后给大家提供@tomayac提供的一个关于color-scheme的Demo[19],下图是dark和light下相应的效果:
这里仅仅是简单的说了一下color-scheme属性,如果想深入的了解还是需要阅读一些相关的教程:
-
CSS Color Adjustment Module Level 1: color-scheme
-
Improved dark mode default styling with the color-scheme CSS property and the corresponding meta tag
-
Don’t Forget the color-scheme Property
其他
▐ & > 和 @nest
很多同学应该使用过像Sass、LESS之类的CSS处理器,这些处理器中有一个特大的特性就是选择器的嵌套,比如Sass中:
.parent {
& > .child {
color: red;
}
}
.child {
.parent & {
color: blue;
}
}
编译之后的CSS:
.parent > .child {
color: red;
}
.parent .child {
color: blue;
}
以往只能在CSS处理器中使用这样的特性,但将来在CSS中也可以使用这方面的特性,因为现在CSS中新增了一个嵌套模块,即 CSS Nesting Module。有点类似于CSS自定义属性(变量)特性一样,最早也是出现在CSS处理器中,现在原生CSS也支持了这方面的特性。
也就是说,在不久的将来(如果在你的工程构建中配置了postcss-preset-env,现在就可以使用):
article, p {
& p {
color: blue;
}
}
相当于:
:is(article, p) p {
color: blue;
}
也就是:
article p,
p p {
color: blue
}
还可以是& >结合起来使用:
article, p {
& > p {
color: blue;
}
}
相当于:
article > p,
p > p{
color: blue;
}
再来看另外几种有效的嵌套方式:
.foo {
color: blue;
& > .bar {
color: red;
}
}
/* 等同于 */
.foo {
color: blue;
}
.foo > .bar {
color: red;
}
.foo {
color: blue;
&.bar {
color: red;
}
}
/* 等同于 */
.foo {
color: blue;
}
.foo.bar {
color: red;
}
.foo, .bar {
color: blue;
& + .baz, &.qux {
color: red;
}
}
/* 等同于 */
.foo, .bar {
color: blue;
}
:is(.foo, .bar) + .baz,
:is(.foo, .bar).qux {
color: red;
}
但是下面这几种写法将是无效的:
/* 无效,因为没有嵌套选择器 */
.foo {
color: red;
.bar {
color: blue;
}
}
/* 无效,因为&不在第一个复合选择器中 */
.foo {
color: red;
.bar & {
color:blue;
}
}
/* 无效,因为列表中的第二个选择器不包含嵌套选择器 */
.foo {
color: red;
&.bar, .baz {
color: blue;
}
}
还可以结合 @nest 使用。下面这几种嵌套方式都是有效的:
.foo {
color: red;
@nest & > .bar {
color: blue;
}
}
/* 等同于 */
.foo {
color: red;
}
.foo > .bar {
color: blue;
}
.foo {
color: red;
@nest .parent & {
color: blue;
}
}
/* 等同于 */
.foo {
color: red;
}
.parent .foo {
color: blue;
}
.foo {
color: red;
@nest :not(&) {
color: blue;
}
}
/* 等同于 */
.foo {
color: red;
}
:not(.foo) {
color: blue;
}
但像下面这样嵌套则是无效的:
/* 无效,因为没有嵌套选择器 */
.foo {
color: red;
@nest .bar {
color: blue;
}
}
/* 无效,因为不是列表中的所有选择器都包含嵌套选择器 */
.foo {
color: red;
@nest & .bar, .baz {
color: blue;
}
}
注意,如果使用@nest时记得要和&结合在一起使用才有效。
▐ @property
在CSS Houdini中,最令人兴奋的是给CSS自定义属性和值的API。这个API通过赋予CSS自定义属性(通常也称为CSS变量)语义意义(由语法定义)甚至回退值来增强CSS自定义属性。
简单地说,可以使用CSS Houdini的CSS自定义属性和值的CSS.registerProperty()来注册一个自定义属性:
CSS.registerProperty({
name: ‘–colorPrimary’,
syntax: ‘’,
initialValue: ‘magenta’,
inherits: false
});
这样一来就可以使用已注册好的–colorPrimary自定义属性:
.card {
background-color: var(–colorPrimary); /* magenta */
}
.highlight-card {
–colorPrimary: yellow;
background-color: var(–colorPrimary); /* yellow */
}
.another-card {
–colorPrimary: 23;
background-color: var(–colorPrimary); /* magenta */
}
现在或者将来,我们可以直接使用CSS的@property来注册一个自定义属性:
@property --gradient-start {
syntax: “”;
initial-value: white;
inherits: false;
}
在CSS中就可以直接像下面这样使用:
.el {
–gradient-start: white;
background: linear-gradient(var(–gradient-start), black);
transition: --gradient-start 1s;
}
.el:hover {
–gradient-start: red;
}
比如下面这个示例[20](请使用Chrome 85+查看):
在CSS的世界中,还有另外一套规范是和CSS自定义属性有关的,那就是 CSS Custom Properties for Cascading Variables Module Level 1。使用–在选择器块中声明自定义属性,然后使用var()函数引用已声明的自定义属性,将其当作CSS属性的值:
:root {
–color: #f09
}
body {
color: var(–color)
}
到目前为止,CSS自定义属性(也有同学称为CSS变量)已经得到了主流浏览器的使用,而且在一些大型Web应用中可以看到其身影。另外CSS自定义属性被运用的场景也很多,比如说@Adam Argyle就用CSS自定义属性模拟了一套缓动函数[21],我们可以用于CSS Animation中:
:root {
–ease-in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53);
–ease-in-cubic: cubic-bezier(0.55, 0.055, 0.675, 0.19);
–ease-in-quart: cubic-bezier(0.895, 0.03, 0.685, 0.22);
–ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06);
–ease-in-expo: cubic-bezier(0.95, 0.05, 0.795, 0.035);
–ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.335);
–ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
–ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
–ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
–ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
–ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
–ease-out-circ: cubic-bezier(0.075, 0.82, 0.165, 1);
–ease-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955);
–ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);
–ease-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1);
–ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);
–ease-in-out-expo: cubic-bezier(1, 0, 0, 1);
–ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.15, 0.86);
–easing: var(–ease-in-quad);
}
.animation__target {
animation: ani 5s var(–easing) alternate infinite;
}
// JavaScript
const handlerElement = document.getElementById(“easing”);
handlerElement.addEventListener(“change”, function (e) {
document.documentElement.style.setProperty(“–easing”, e.target.value);
});
查看效果[22]:
▐ ::cue和::cue(selector)
::cue和::cue(selector)对我而言是一个全新的东西,这两个伪元素是 WebVTT: The Web Video Text Tracks Format 模块中的。
::cue和::cue(selector)两个伪元素最大的差别是后者带参数的伪元素。具体的作用:
-
::cue伪元素(不带参数)匹配元素构造的任何WebVTT节点对象列表,但与背景符号对应的属性必须应用于WebVTT线索背景框,而不是WebVTT节点对象列表。
-
::cue(selector)是带有参数的伪元素,必须有一个由CSS选择器组成的参数。它匹配元素构造的WebVTT内部节点对象,该元素也匹配给定的CSS选择器。
在CSS中只有部分属性可以运用于::cue和::cue(selector)两个伪元素,比如color、opacity、visibility、text-decoration、text-shadow、background、outline、font、line-height、white-space、text-combine-upright和ruby-position等。
::cue {
color: white;
background-color: hsl(0 0% 0% / 90%);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(资料价值较高,非无偿)
完整版面试题资料分享,只需你点赞支持,动动手指点击此处就可免费领取了。
回顾项目
往往在面试时,面试官根据你简历中的项目由点及面地展开问答,所以请对你做过的最好的项目进行回顾和反思。回顾你做过的工作和项目中最复杂的部分,反思你是如何完成这个最复杂的部分的。
面试官会重点问你最复杂的部分的实现方法和如何优化。重点要思考如何优化,即使你项目中没有对那部分进行优化,你也应该预先思考有什么优化的方案。如果这部分答好了,会给面试官留下很不错的印象。
重点在于基础知识
这里指的基础知识包括:前端基础知识和学科基础知识。
前端基础知识:html/css/js 的核心知识,其中 js 的核心知识尤为重要。比如执行上下文、变量对象/活动对象(VO/AO)、作用域链、this 指向、原型链等。
学科基础知识:数据结构、计算机网络、算法等知识。你可能会想前端不需要算法,那你可能就错了,在大公司面试,面试官同样会看重学生这些学科基础知识。
你可能发现了我没有提到React/Vue
这些框架的知识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。er(“change”, function (e) {
document.documentElement.style.setProperty(“–easing”, e.target.value);
});
查看效果[22]:
▐ ::cue和::cue(selector)
::cue和::cue(selector)对我而言是一个全新的东西,这两个伪元素是 WebVTT: The Web Video Text Tracks Format 模块中的。
::cue和::cue(selector)两个伪元素最大的差别是后者带参数的伪元素。具体的作用:
-
::cue伪元素(不带参数)匹配元素构造的任何WebVTT节点对象列表,但与背景符号对应的属性必须应用于WebVTT线索背景框,而不是WebVTT节点对象列表。
-
::cue(selector)是带有参数的伪元素,必须有一个由CSS选择器组成的参数。它匹配元素构造的WebVTT内部节点对象,该元素也匹配给定的CSS选择器。
在CSS中只有部分属性可以运用于::cue和::cue(selector)两个伪元素,比如color、opacity、visibility、text-decoration、text-shadow、background、outline、font、line-height、white-space、text-combine-upright和ruby-position等。
::cue {
color: white;
background-color: hsl(0 0% 0% / 90%);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-JOB6VOx5-1711646618644)]
[外链图片转存中…(img-OnMOB9b6-1711646618645)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
[外链图片转存中…(img-x6q5T6ox-1711646618645)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(资料价值较高,非无偿)
完整版面试题资料分享,只需你点赞支持,动动手指点击此处就可免费领取了。
回顾项目
往往在面试时,面试官根据你简历中的项目由点及面地展开问答,所以请对你做过的最好的项目进行回顾和反思。回顾你做过的工作和项目中最复杂的部分,反思你是如何完成这个最复杂的部分的。
面试官会重点问你最复杂的部分的实现方法和如何优化。重点要思考如何优化,即使你项目中没有对那部分进行优化,你也应该预先思考有什么优化的方案。如果这部分答好了,会给面试官留下很不错的印象。
重点在于基础知识
这里指的基础知识包括:前端基础知识和学科基础知识。
前端基础知识:html/css/js 的核心知识,其中 js 的核心知识尤为重要。比如执行上下文、变量对象/活动对象(VO/AO)、作用域链、this 指向、原型链等。
学科基础知识:数据结构、计算机网络、算法等知识。你可能会想前端不需要算法,那你可能就错了,在大公司面试,面试官同样会看重学生这些学科基础知识。
你可能发现了我没有提到React/Vue
这些框架的知识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。-