diff --git a/CSS Layout/CSS Layout Note.md b/CSS Layout/CSS Layout Note.md new file mode 100644 index 0000000..2cfa72b --- /dev/null +++ b/CSS Layout/CSS Layout Note.md @@ -0,0 +1,22 @@ +# CSS Layout Note + +**Float、Grid、Flex、position、display 和盒模型**是用于制作布局的一些关键主题。 + +以下是一些关于这方面的资料: + +- [Introduction to CSS layout](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Introduction) +- [学习 CSS 布局](https://zh.learnlayout.com/) +- [A Complete Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) +- [Flex 布局](https://github.com/lio-zero/blog/blob/main/CSS/Flex%20%E5%B8%83%E5%B1%80.md) +- [The box model](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model) +- [The CSS Display Property - Display None, Display Table, Inline Block and More](https://www.freecodecamp.org/news/the-css-display-property-display-none-display-table-inline-block-and-more/) +- [FLEXBOX FROGGY](https://flexboxfroggy.com/) +- [A Complete Guide to Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) +- [GRID GARDEN](https://cssgridgarden.com/) +- [All About Floats](https://css-tricks.com/all-about-floats/) +- [Absolute, Relative, Fixed Positioning: How Do They Differ?](https://css-tricks.com/absolute-relative-fixed-positioining-how-do-they-differ/) +- [Understanding Flexbox: Everything you need to know](https://www.freecodecamp.org/news/understanding-flexbox-everything-you-need-to-know-b4013d4dc9af#.pr6cltk9j) +- [CSS Flexible Box Layout](https://www.w3.org/TR/css-flexbox-1/) 和 [CSS Grid Layout](https://www.w3.org/TR/css-grid-1/) 规范。 +- [The Holy Grail Layout with CSS Grid](https://bitsofco.de/holy-grail-layout-css-grid/) +- [magic-of-css](https://adamschwartz.co/magic-of-css/) +- [CSS Grid and Grid Highlighter Now in Firefox Developer Edition](https://hacks.mozilla.org/2016/12/css-grid-and-grid-highlighter-now-in-firefox-developer-edition/) diff --git "a/CSS Layout/CSS \345\244\232\345\210\227\357\274\210column\357\274\211.md" "b/CSS Layout/CSS \345\244\232\345\210\227\357\274\210column\357\274\211.md" new file mode 100644 index 0000000..143170a --- /dev/null +++ "b/CSS Layout/CSS \345\244\232\345\210\227\357\274\210column\357\274\211.md" @@ -0,0 +1,93 @@ +# CSS 多列(column) + +CSS `columns` 属性用来设置元素的列宽和列数。 + +## 浏览器支持情况 + +## 相关属性 + +- `column-width: ` 列的宽度。 +- `column-count: | auto` 指定元素的列数。 +- `columns` 为 `column-width` 和 `column-count` 的简写形式 +- `column-rule-style` 指定两列间边框的样式 +- `column-rule-width` 指定两列间边框的厚度 +- `column-rule-color` 指定两列间边框的颜色 +- `column-rule` 为上面三个的简写形式,规定列之间的宽度、样式和颜色。 +- `column-gap` 控制列之间的距离 +- `column-span: none | all` 指定元素要跨越多少列 +- `column-fill: all | balanced` 指定如何填充列 + +您可以使用 `break-before`,`break-after` 或者 `break-inside` 来如何控制每一列中的内容显示。 + +默认情况下,列与内容保持平衡。如果您希望列不平衡,可以使用 `column-fill: auto` 进行设置。其默认行为为 `column-fill: balanced`。 + +```css +.container { + width: 300px; + margin: 100px auto; + columns: 8; + column-rule: 1px dashed rgb(213, 213, 213); + direction: rtl; + word-wrap: break-word; + text-align: center; +} +``` + +> [查看效果](https://codepen.io/lio-zero/pen/mdRpNjm) + +我们再来看看两个例子。 + +## 三列 + +```html +
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos pariatur sunt + consequatur vitae corrupti dolores praesentium sapiente dolorum laudantium + dolor ut natus, cum animi, cumque molestias libero eius nobis! Quod, veniam. + Velit quo quos repudiandae minus est quaerat recusandae maiores impedit labore + asperiores numquam amet, libero in dolorem cupiditate! Repudiandae impedit + corporis sapiente sint velit similique, voluptatum cum nemo est magnam non + ratione aliquam adipisci error perspiciatis voluptas quos dicta voluptatibus + suscipit nam. Ad labore nihil sint quisquam eum corrupti nam. Explicabo, + commodi. Labore molestias reiciendis vitae eos, iste possimus odio, voluptates + quasi nam, voluptate est? Odio architecto doloribus quia. +
+``` + +CSS 如下: + +```css +.three-col { + column-count: 3; + column-gap: 20px; + column-rule: 1px dashed #ccc; +} +``` + +## 导航栏 + +```css +.nav { + columns: 100px 4; + column-gap: 0; + column-rule: 1px solid #1a242f; + background: #2c3e50; +} + +.nav a { + display: block; + padding: 1em; + border-bottom: 1px solid #1a242f; + color: white; + text-align: center; + text-decoration: none; +} + +.nav a:hover { + background: #1a242f; +} +``` + +> [查看效果](https://codepen.io/lio-zero/pen/zYNROYG) + +你可以查阅 [When And How To Use CSS Multi-Column Layout](https://www.smashingmagazine.com/2019/01/css-multiple-column-layout-multicol/) 以了解更多关于这方面的内容。 diff --git "a/CSS Layout/CSS \345\261\205\344\270\255.md" "b/CSS Layout/CSS \345\261\205\344\270\255.md" new file mode 100644 index 0000000..48dc0d1 --- /dev/null +++ "b/CSS Layout/CSS \345\261\205\344\270\255.md" @@ -0,0 +1,206 @@ +# CSS 居中 + +基本结构如下: + +```html +
+
+
+``` + +基本样式如下: + +```css +.container { + width: 200px; + height: 200px; + background-color: pink; +} + +.box { + width: 50px; + height: 50px; + background-color: plum; +} +``` + +## table-cell + +```css +.container { + display: table-cell; + vertical-align: middle; +} + +.box { + margin: auto; +} +``` + +或者: + +```css +.container { + display: table-cell; + text-align: center; + vertical-align: middle; +} + +.box { + display: inline-block; +} +``` + +## position + +**未知宽度和高度的元素**,可以使用绝对定位和 `transform` 属性的 `translate`。 + +```css +.container { + position: relative; +} + +.box { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} +``` + +`transform` 还可以使用 `margin` 代替,但需要提前知道元素的宽高: + +```css +.container { + position: relative; +} + +.box { + position: absolute; + top: 50%; + left: 50%; + margin: -25px 0 0 -25px; // width 和 height 的负一半 +} +``` + +另一种方式,设置 `absolute` 的偏移值(`top`、`left`、`right` 和 `bottom`)为 `0`,并使用 `margin: auto`,好处是不需要提前知道元素的尺寸兼容性好。 + +```css +.container { + position: relative; +} + +.box { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: auto; +} +``` + +## Flex + +使用 `justify-content` 和 `align-item`: + +```css +.container { + display: flex; + justify-content: center; + align-items: center; +} +``` + +使用 `justify-content` 和 `align-self`: + +```css +.container { + display: flex; + justify-content: center; +} + +.box { + align-self: center; +} +``` + +使用 `margin: auto`: + +```css +.container { + display: flex; +} + +.box { + margin: auto; +} +``` + +## 使用 Grid 居中 + +`grid` 用于二维布局,但当只有一个子元素时,一维布局与二维布局都一样。 + +```css +.container { + display: grid; + justify-content: center; + align-content: center; +} +/* or */ +.container { + display: grid; + justify-items: center; + align-items: center; +} +``` + +上面属性的简写形式: + +```css +.container { + display: grid; + place-items: center; +} +/* or */ +.container { + display: grid; + place-content: center; +} +``` + +更简便的技巧: + +```css +.container { + display: grid; +} + +.box { + margin: auto; +} +``` + +另一种方式,我们可以单独控制子元素的对齐方式: + +```css +.container { + display: grid; +} + +.box { + align-self: center; + justify-self: center; + /* 简写形式 */ + /* place-self: center; */ +} +``` + +搭配众多,一个个尝试。 + +> [演示地址](https://codepen.io/lio-zero/pen/XWVyqjZ) + +## 更多资料 + +- [Centering in CSS: A Complete Guide](https://css-tricks.com/centering-css-complete-guide/) +- [How to horizontally center an element](https://stackoverflow.com/questions/114543/how-to-horizontally-center-an-element) diff --git "a/CSS Layout/\344\270\211\346\240\217\345\270\203\345\261\200.md" "b/CSS Layout/\344\270\211\346\240\217\345\270\203\345\261\200.md" new file mode 100644 index 0000000..f2625fe --- /dev/null +++ "b/CSS Layout/\344\270\211\346\240\217\345\270\203\345\261\200.md" @@ -0,0 +1,114 @@ +# 三栏布局 + +**三栏布局,左右两栏宽度固定,中间栏宽度自适应。** + +假设我们有以下 HTML 结构: + +```html +
+ +
+ +
+``` + +基本样式如下: + +```css +html, +body { + height: 100%; + margin: 0; +} + +.container, +.left, +.right, +.content { + height: 100%; + overflow: auto; +} +``` + +本文将介绍几种实现三栏布局的方式。 + +## 使用 `float` + +```css +.left { + width: 210px; + float: left; +} + +.right { + float: right; + width: 210px; +} +``` + +这里会有一点不一样,我们需要调整一下类为 `.right` 标签的位置。 + +```html + + +
+``` + +> **注意**:使用 `float` 实现的三栏布局挤压到一定的宽度时,也会存在发生变形情况,这时需要额外进行处理。 + +## 使用 `position` + +```css +.container { + position: relative; +} + +.left { + position: absolute; + top: 0; + left: 0; + width: 210px; +} + +.content { + margin: 0 210px; +} + +.right { + position: absolute; + top: 0; + right: 0; + width: 210px; +} +``` + +## 使用 `flex` + +```css +.container { + display: flex; +} + +.left { + width: 210px; +} + +.content { + flex: 1; +} + +.right { + width: 210px; +} +``` + +## 使用 `grid` + +```css +.container { + display: grid; + grid-template-columns: 210px 1fr 210px; +} +``` + +> [查看效果](https://codepen.io/lio-zero/pen/abEQXdr) diff --git "a/CSS Layout/\344\276\247\350\276\271\346\240\217\345\270\203\345\261\200.md" "b/CSS Layout/\344\276\247\350\276\271\346\240\217\345\270\203\345\261\200.md" new file mode 100644 index 0000000..7e6daaf --- /dev/null +++ "b/CSS Layout/\344\276\247\350\276\271\346\240\217\345\270\203\345\261\200.md" @@ -0,0 +1,103 @@ +# 侧边栏布局 + +侧边栏布局,它包含一个边栏(固定的),一个主栏(可滚动的)。 + +```html +
+ + + + +
...
+
+``` + +基本样式如下: + +```css +html, +body { + height: 100%; + margin: 0; +} + +.container, +.container__sidebar, +.container__main { + height: 100%; +} +``` + +## 使用 `float` 和 `margin` + +```css +.container__sidebar { + width: 210px; + float: left; +} + +.container__sidebar { + margin-left: 210px; + overflow: auto; +} +``` + +## 使用 `float` 和 `calc()` + +```css +.container__sidebar { + width: 210px; + float: left; +} +.container__main { + width: calc(100% - 210px); + overflow: auto; +} +``` + +## 使用 `absolute` + +```css +.container__sidebar { + position: absolute; + left: 0; + top: 0; + width: 30%; +} + +.container__main { + position: absolute; + right: 0; + top: 0; + width: calc(100% - 30%); + overflow: auto; +} +``` + +## 使用 `flex` + +```css +.container { + display: flex; +} + +.container__sidebar { + width: 30%; +} + +.container__main { + flex: 1; + overflow: auto; +} +``` + +## 使用 `grid` + +```css +.container { + display: grid; + grid-template-columns: minmax(150px, 30%) 1fr; +} +``` + +> [查看效果](https://codepen.io/lio-zero/pen/yLVmWRY) diff --git "a/CSS Layout/\345\215\241\347\211\207\345\270\203\345\261\200.md" "b/CSS Layout/\345\215\241\347\211\207\345\270\203\345\261\200.md" new file mode 100644 index 0000000..d637c52 --- /dev/null +++ "b/CSS Layout/\345\215\241\347\211\207\345\270\203\345\261\200.md" @@ -0,0 +1,93 @@ +# 卡片布局 + +基本结构如下: + +```html +
+
+
+
+
+
+
+
+
+
+
+``` + +基本样式如下: + +```css +html, +body { + height: 100%; + margin: 0; +} + +.cards { + height: 100%; +} + +.cards__item { + background: pink; + height: calc(33.33% - 16px); + width: calc(33.33% - 16px); + margin: 8px; + border-radius: 0.25rem; +} + +.cards__item:nth-child(odd) { + background: plum; +} +``` + +这里的卡片布局,其实根据你想要控制元素的占据所决定,本示例每行、每列各占三个元素。 + +## 使用 `absolute` + +```css +.cards { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; +} + +.item { + /* ... */ + float: left; + height: 33.33%; + width: 33.33%; +} +``` + +> [查看效果](https://codepen.io/lio-zero/pen/NWdyPPg) + +## Flex + +`display: flex` 设置容器成 Flex 布局,`flex-wrap:` 设置元素可换行。 + +```css +.cards { + display: flex; + flex-wrap: wrap; +} +``` + +> [查看效果](https://codepen.io/lio-zero/pen/mdRXbKj) + +## Grid + +`grid-template-columns` 控制元素的列占据,`grid-template-rows` 控制元素的行占据,它们都用于父元素。 + +```css +.container { + display: grid; + grid-template-columns: repeat(3, 33.33%); + grid-template-rows: repeat(3, 33.33%); +} +``` + +> [查看效果](https://codepen.io/lio-zero/pen/rNjJBdL) diff --git "a/CSS Layout/\345\233\272\345\256\232\345\244\264\351\203\250.md" "b/CSS Layout/\345\233\272\345\256\232\345\244\264\351\203\250.md" new file mode 100644 index 0000000..5cb6beb --- /dev/null +++ "b/CSS Layout/\345\233\272\345\256\232\345\244\264\351\203\250.md" @@ -0,0 +1,35 @@ +# 固定头部 + +```html +
+
+
+
+``` + +我们可以使用定位的两种方式来固定头部。 + +## Fixed + +```css +header { + position: fixed; + top: 0; + width: 100%; +} + +main { + margin-top: 50px; +} +``` + +## Sticky + +```css +header { + position: sticky; + top: 0; +} +``` + +> [测试效果](https://codepen.io/lio-zero/pen/yLPvgLo) diff --git "a/CSS Layout/\345\233\272\345\256\232\351\241\265\350\204\232.md" "b/CSS Layout/\345\233\272\345\256\232\351\241\265\350\204\232.md" new file mode 100644 index 0000000..81c6a47 --- /dev/null +++ "b/CSS Layout/\345\233\272\345\256\232\351\241\265\350\204\232.md" @@ -0,0 +1,126 @@ +# 固定页脚 + +假设我们的页面由三部分组成:页眉、主要内容和页脚。无论主要内容有多长,页脚总是显示在底部是一种常见的布局。 + +```html +
+
+
+
+
+``` + +基本样式: + +```css +html, +body, +.container { + height: 100%; +} + +body { + margin: 0; +} +``` + +## 使用 `margin` + +- 内容区域的 `margin-bottom` 为负值 + +```css +.content { + min-height: 100%; + margin-bottom: -50px; +} + +.footer { + height: 50px; +} +``` + +- 页脚的 `margin-top` 为负高度大小 + +```css +main { + min-height: 100%; +} + +footer { + height: 50px; + margin-top: -50px; +} +``` + +## 使用 `calc()` + +```css +main { + min-height: calc(100% - 50px); +} + +footer { + height: 50px; +} +``` + +## 使用 `flex` + +使用 CSS `flex`,布局实现如下: + +```css +.container { + display: flex; + flex-direction: column; +} + +main { + flex-grow: 1; + /* flex: 1 0 auto; */ +} + +footer { + flex-shrink: 0; +} +``` + +设置 `flex-grow: 1` 为主要内容将使其占用可用空间。 + +或者使用 `margin: auto`: + +```css +.container { + display: flex; + flex-direction: column; +} + +footer { + margin-top: auto; +} +``` + +## 使用 `grid` + +```css +.container { + display: grid; + min-height: 100%; + grid-template-rows: auto 1fr auto; +} +``` + +> [查看效果](https://codepen.io/lio-zero/pen/podprXj) + +## sticky + +```css +footer { + position: sticky; + top: 100vh; +} +``` + +## 更多资料 + +- [Sticky Footer, Five Ways](https://css-tricks.com/couple-takes-sticky-footer/) +- [A Clever Sticky Footer Technique](https://css-tricks.com/a-clever-sticky-footer-technique/) diff --git "a/CSS Layout/\345\233\276\347\211\207\345\222\214\346\226\207\345\255\227\345\236\202\347\233\264\345\261\205\344\270\255.md" "b/CSS Layout/\345\233\276\347\211\207\345\222\214\346\226\207\345\255\227\345\236\202\347\233\264\345\261\205\344\270\255.md" new file mode 100644 index 0000000..68d65ec --- /dev/null +++ "b/CSS Layout/\345\233\276\347\211\207\345\222\214\346\226\207\345\255\227\345\236\202\347\233\264\345\261\205\344\270\255.md" @@ -0,0 +1,39 @@ +# 图片和文字垂直居中 + +```html + +

lorem

+``` + +`vertical-align` 属性经常用于表单或图片和文字垂直对齐,`middle` 可以将元素放置在父元素的居中位置。 + +```css +img { + display: inline-block; + vertical-align: middle; +} + +p { + display: inline-block; +} +``` + +![image.png](https://upload-images.jianshu.io/upload_images/18281896-9596e459912f879d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +`vertical-align` 属性各个值的所对应的基线: + +![vertical-align 属性](https://upload-images.jianshu.io/upload_images/18281896-79fb680691076a8c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +**扩展**:`vertical-align` 属性还可用于解决图片底部默认空白缝隙问题,原因是行内块元素会和文字的基线对齐。 + +解决方法有两种: + +- 将图片转为块级元素 `display: block` +- 给图片添加 `vertical-align: middle | top | bottom` + +--- + +Chris Coyier 提供了一种使用 Grid 布局技巧来使图片和文字垂直居中的方法:[How do you make a layout with pictures down one side of a page matched up with paragraphs on the other side?](https://css-tricks.com/how-do-you-make-a-layout-with-pictures-down-one-side-of-a-page-matched-up-with-paragraphs-on-the-other-side/)。 diff --git "a/CSS/BEM \345\221\275\344\273\244\350\247\204\350\214\203.md" "b/CSS/BEM \345\221\275\344\273\244\350\247\204\350\214\203.md" new file mode 100644 index 0000000..07af340 --- /dev/null +++ "b/CSS/BEM \345\221\275\344\273\244\350\247\204\350\214\203.md" @@ -0,0 +1,130 @@ +# BEM 命名规范 + +众所周知,CSS 在大型、复杂、快速迭代的系统中难以管理。有多种编写 CSS 的方法可以编写更易于维护的 CSS。 + +本文将来了解 CSS BEM 命名规范。 + +BEM 是一种前端项目开发的方法论,由 [Yandex](http://yandex.ru/) 公司提出。 + +BEM 的名称来源于该方法学的三个组成部分的英文首字母,分别是块(Block)、元素(Element)和修饰符(Modifier)。 + +这里先推荐一篇关于使用 BEM 的组件命名规范的示例文章:[bem naming cheat sheet by 9elements](https://9elements.com/bem-cheat-sheet/#form-blocks)。 + +![bem naming cheat sheet by 9elements](https://upload-images.jianshu.io/upload_images/18281896-17eb45f3195525d4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +其中介绍了包括:面包屑、按钮、卡片、列表、导航、布局、表单控件等一些组件的结构、命名示例。 + +## 什么是 CSS BEM? + +**[BEM](https://bem.info/)**(Block Element Modifier,块元素修饰符)是 CSS 类的命名约定,旨在通过定义命名空间来解决范围问题来使 CSS 更具可维护性。 + +它原则上建议为独立的 CSS 类命名,并且在需要层级关系时,将关系也体现在命名中,这自然会使选择器高效且易于覆盖。 + +- block(块)是一个独立的组件,可在项目中重复使用,并充当子组件(元素)的 "命名空间"。 +- 当 block(块)或 element(元素)处于特定状态或结构或样式不同时,将 modifier(修饰符)用作标志。 + +## BEM 命名约定 + +- `block` 代表了更高级别的抽象或组件。 +- `block__element` 代表 `.block` 的后代,用于形成一个完整的 .block 的整体。 +- `block--modifier` 代表 `.block` 的不同状态或不同版本。 + +```css +.block {} +.block__element {} +.block--modifier {} +``` + +## 示例 + +- BEM 实体名称全部是小写字母或数字。名称中的不同单词用单个连字符(`-`)分隔。 +- BEM 元素名称和块名称之间通过两个下划线(`__`)分隔。 +- 布尔修饰符和其所修饰的实体名称之间通过两个连字符(`--`)来分隔。不使用名值对修饰符。 + +```html + +``` + +CSS 如下: + +```css +.menu { + list-style: none; +} +.menu__item { + font-weight: bold; +} +.menu__item--selected { + color: plum; +} +``` + +分析: + +- `.menu` 封装一个独立的实体,它本身是有意义的。虽然块可以嵌套并相互交互,但在语义上它们是相等的;没有优先级或等级制度。 +- `.menu__item` 块的一部分,没有独立的意义。任何元素在语义上都与其块相关联。 +- `.menu__item--selected` 块或元素上的修饰符。使用它们来改变外观、行为或状态。 + +## BEM 命名规范带来的好处 + +BEM 的优点在于所产生的 CSS 类名都只使用一个类别选择器,可以避免传统做法中由于多个类别选择器嵌套带来的复杂的属性级联问题。 + +换句话说,其所有样式规则的**特异性(specificity)**都是相同的,也就不存在复杂的优先级问题,简化了层叠规则。如果你还不是很了解特异性的话,可以查阅之前写的一篇 [CSS 继承、级联和特异性](https://github.com/lio-zero/blog/blob/master/CSS/CSS%20%E7%BB%A7%E6%89%BF%E3%80%81%E7%BA%A7%E8%81%94%E5%92%8C%E7%89%B9%E5%BC%82%E6%80%A7.md)。 + +细分后,可以从**模块化**、**可重用性**、**结构**三部分进行理解: + +- **模块化**:块样式从不依赖于页面上的其他元素,因此您将永远不会遇到级联带来的问题。 +- **可重用性**:以不同的方式构成独立的块,并以智能方式对其进行重用,从而减少了必须维护的 CSS 代码量。 +- **结构**:BEM 方法为您的 CSS 代码提供了坚实的结构,使结构保持简单易懂。 + +## 其他的一些命名规范 + +除了 BEM 以外,还有其他一些常用命名规范如:[OOCSS](http://oocss.org/)、[SMACSS](https://smacss.com/) 等。 + +### OOCSS + +OOCSS 表示的是面向对象 CSS(**Object Oriented CSS**),是一种把面向对象方法学应用到 CSS 代码组织和管理中的实践 + +**OOCSS 有两个重要的原则**: + +- 第一个原则是把结构和外观分开。 +- 第二个原则是把容器和内容分开。 + +### SMACSS + +SMACSS 表示的是可扩展和模块化 CSS(**Scalable and Modular Architecture for CSS**)。 + +SMACSS 把 CSS 样式规则分成若干个不同的类别: + +- **基础**:该类别中包含的是默认的 CSS 样式。作为其他样式的基础。 +- **布局**:该类别中包含与页面布局相关的 CSS 样式,用来进行模块的排列。 +- **模块**:该类别中包含的是可复用的模块的 CSS 样式。 +- **状态**:该类别中的 CSS 样式用来描述布局和模块在不同状态下的外观。比如在不同的屏幕尺寸下,布局会发生变化。标签式模块的每个标签页可以有显示或隐藏的状态。 +- **主题**:该类别和状态类似,只不过是用来改变布局和模块的视觉效果。 + +## CSS 架构 + +这一节总结一下目前前端的一些 CSS 架构: + +- [BEM](http://getbem.com/) +- [CSS Modules](https://github.com/css-modules/css-modules) +- [Atomic](https://acss.io/) +- [OOCSS](https://github.com/stubbornella/oocss/wiki) +- [SMACSS](https://smacss.com/) +- [SUITCSS](https://suitcss.github.io/) + +另外,可以了解一下近几年很火的 [CSS-in-JS](https://github.com/lio-zero/blog/blob/main/WTF/%E4%BB%80%E4%B9%88%E6%98%AF%20CSS-in-JS.md)。 + +## 更多资源 + +- [A Look at Some CSS Methodologies](https://www.webfx.com/blog/web-design/css-methodologies/) +- [如何看待 CSS 中 BEM 的命名方式?](https://www.zhihu.com/question/21935157/answer/20116700) +- [BEMIT: Taking the BEM Naming Convention a Step Further](https://csswizardry.com/2015/08/bemit-taking-the-bem-naming-convention-a-step-further/) +- [BEM Docs](https://en.bem.info/methodology/quick-start) +- [BEM 101](https://css-tricks.com/bem-101) +- [BEM TUTORIALS](https://en.bem.info/tutorials/) +- [Modern alternatives to BEM](https://daverupert.com/2022/08/modern-alternatives-to-bem/) diff --git "a/CSS/BFC \345\217\212\345\205\266\345\272\224\347\224\250.md" "b/CSS/BFC \345\217\212\345\205\266\345\272\224\347\224\250.md" new file mode 100644 index 0000000..7b82bc6 --- /dev/null +++ "b/CSS/BFC \345\217\212\345\205\266\345\272\224\347\224\250.md" @@ -0,0 +1,137 @@ +# BFC 及其应用 + +> **块格式化上下文(Block Formatting Context,BFC)** 是 Web 页面的可视化 CSS 渲染的一部分。它是布局过程中生成块级盒子的区域,也是浮动元素与其他元素的交互限定区域。 + +## BFC 特性 + +- BFC 在 Web 页面上是一个独立的容器,容器内外的元素互不影响 +- 和标准文档流一样,BFC 内的两个相邻块级元素垂直方向的边距会发生重叠 +- BFC 不会与浮动元素的盒子重叠 +- BFC 在计算高度时会把浮动元素计算进去 + +## 触发 BFC + +只要元素满足下面任一条件即可触发 BFC 特性([详细](https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context)): + +- 根元素(``) +- 浮动元素(元素的 `float` 不是 `none`) +- 绝对定位元素(元素的 position 为 absolute 或 fixed) +- `display 为 `inline-block`、`table-cells`、`flex`、`grid`... +- `overflow` 值不为 `visible` 的块元素(`hidden`、`auto`、`scroll`) +- ... + +## BFC 应用 + +### 清除浮动 + +当父元素没有设置高度,且子元素为浮动元素的情况下,父元素会发生高度坍塌,上下边界重合,即浮动元素无法撑开父元素。 + +```html +
+
+
+``` + +给子元素设置浮动: + +```css +.child { + float: left; +} +``` + +![高度塌陷](https://upload-images.jianshu.io/upload_images/18281896-ffb7fb17c3520e66.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +可以看到,子元素浮动后,父元素失去了高度。 + +**为了解决浮动元素造成的父元素高度塌陷问题,可以将父元素设置成一个 BFC 来清除浮动,将父元素整体设置为 BFC 环境。** + +```css +.parent { + overflow: auto; +} +``` + +![清除浮动](https://upload-images.jianshu.io/upload_images/18281896-0189447c6531425c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +[查看效果](https://codepen.io/lio-zero/pen/bGgzaqR) + +### 元素浮动后发生重叠 + +```html +
+
+``` + +给第一个盒子设置浮动: + +```css +.box1 { + float: left; +} +``` + +![元素重叠](https://upload-images.jianshu.io/upload_images/18281896-48d1b6e1b66290bf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +可以看到,由于 `box1` 发生浮动,`box2` 未发生浮动,而浮动元素由于脱离文档流,第一个盒子堆叠在第二个盒子上。 + +为了让两个元素不重叠,我们把右边的盒子设置成 BFC: + +```css +.box2 { + overflow: hidden; +} +``` + +![元素重叠](https://upload-images.jianshu.io/upload_images/18281896-7b9a994b9b3b3629.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +[查看效果](https://codepen.io/lio-zero/pen/zYNePmj) + +### 外边距重叠 + +在标准文档流中,毗邻的两个或多个块级元素之间垂直方向的 `margin` 会合并成一个 `margin`,会取两个元素 `margin` 最大的那一个,这就是外边距重叠。 + +有三种情况会形成[外边距重叠](https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing)(Margin collapsing): + +- **同一层相邻元素之间** +- **没有内容将父元素和后代元素分开** +- **空的块级元素** + +而创建了块级格式化上下文(BFC)的元素,不会和它的子元素发生 `margin` 重叠。 + +我们可以使用例如 `overflow:hidden` 来产生一个 BFC 环境来解决该问题。 + +```html +
+
+``` + +给两个 `
` 元素设置外边距: + +```css +div { + margin: 50px; +} +``` + +![外边距重叠](https://upload-images.jianshu.io/upload_images/18281896-054cc08fc4e02d92.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +可以看到,第一个元素的下边距和第二个元素的上边距发生了重叠。 + +**解决边距重叠的问题,可以将其放在不同的 BFC 容器中。** + +```html +
+
+
+ +
+
+
+``` + +![外边距重叠](https://upload-images.jianshu.io/upload_images/18281896-38aad629ee81ee4d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +因为 BFC 是一个独立的容器,容器内外互不影响。 + +[查看效果](https://codepen.io/lio-zero/pen/QWdYapO) diff --git a/CSS/CSS @Supports.md b/CSS/CSS @Supports.md new file mode 100644 index 0000000..c966334 --- /dev/null +++ b/CSS/CSS @Supports.md @@ -0,0 +1,116 @@ +# CSS @Supports + +CSS [`@supports`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/@supports) 指令会像 `@media` 查询一样出现在 CSS 代码中: + +```css +@supports (prop: value) { + /* more styles */ +} +``` + +CSS `@supports` 允许开发人员以多种不同的方式检查样式支持。 + +例如:检查是否支持 `display: flex`: + +```css +@supports (display: flex) { + div { + display: flex; + } +} +``` + +## not 关键字 + +`@supports` 可以与 `not` 关键字一起使用,以检查是否不支持: + +```css +@supports not (display: flex) { + div { + float: left; + } +} +``` + +## 多重检查和条件 + +可以通过 `or` 和 `and` 链接进行多个 CSS 属性检查: + +```css +/* or */ +@supports (display: -webkit-flex) or (display: -moz-flex) or (display: flex) { + /* use styles here */ +} + +/* and */ +@supports (display: flex) and (-webkit-appearance: caret) { + /* something crazy here */ +} +``` + +两者一起使用: + +```css +/* and 和 or */ +@supports ((display: -webkit-flex) or (display: -moz-flex) or (display: flex)) + and (-webkit-appearance: caret) { + /* use styles here */ +} +``` + +`@supports` 结构的条件模式与 `@media` 的条件模式匹配。 + +## JavaScript `CSS.supports` + +CSS `@supports` 对应的 JavaScript 是 [`CSS.supports`](https://developer.mozilla.org/zh-CN/docs/Web/API/CSS/supports)。`CSS.supports` 提供了两种使用方法。 + +- 第一种使用方法包括提供两个参数:一个用于属性,另一个用于值: + +```js +const supportsFlex = CSS.supports('display', 'flex') +``` + +- 第二种用法包括简单地提供要分析的整个字符串: + +```js +const supportsFlexAndAppearance = CSS.supports( + '(display: flex) and (-webkit-appearance: caret)' +) +``` + +您可以通过这两种方法来检查 CSS 支持情况,它避免了在临时节点上进行属性检查,也避免了为检查支持而构建字符串。 + +在使用 `supports` 的 JavaScript 方法之前,首先检测功能是很重要的。Opera 使用了一个不同的方法名,因此会抛出一些东西: + +```js +const supportsCSS = !!( + (window.CSS && window.CSS.supports) || + window.supportsCSS || + false +) +``` + +## @Supports 使用 + +在大多数情况下,`@supports` 的最佳用途是将一组较旧的样式设置为备份,然后取消这些样式,并在支持给定属性的情况下进行增强。 + +`@supports` 的一个优秀用例是布局。一些边缘浏览器现在提供对 `flexbox` 的支持,而其他浏览器则落后。在这种情况下,您可以编写以下代码: + +```css +section { + float: left; +} + +@supports (display: -webkit-flex) or (display: -moz-flex) or (display: flex) { + section { + display: -webkit-flex; + display: -moz-flex; + display: flex; + float: none; + } +} +``` + +随着开发人员有更多时间尝试新的 `@supports` 功能,其他良好的用例也会出现。 + +> [MDN 提供了更多示例](https://developer.mozilla.org/en-US/docs/Web/CSS/@supports#examples) diff --git "a/CSS/CSS Bulma \346\241\206\346\236\266.md" "b/CSS/CSS Bulma \346\241\206\346\236\266.md" new file mode 100644 index 0000000..62d2f4e --- /dev/null +++ "b/CSS/CSS Bulma \346\241\206\346\236\266.md" @@ -0,0 +1,199 @@ +# CSS Bulma 框架 + +[Bulma](https://bulma.io/) 是一个免费的、开源的框架,采用了移动优先的响应式布局,它提供了可随时使用的前端组件,您可以轻松地将这些组件组合起来构建响应性强的 web 界面。 + +Bluma 可以作为 Bootstrap 的替代框架,这类框架还有 [Skeleton](http://getskeleton.com/)、[Pure](https://purecss.io/)、[Bootflat](http://bootflat.github.io/)、[Mueller](https://muellergridsystem.com/)。 + +Bluma 是纯 CSS 的框架,你只需要将已经给定的类添加到你的标签中,就能实现漂亮的效果。 + +下面我们将来介绍它。 + +## 安装 + +### 使用 NPM + +```bash +npm install bulma +``` + +安装后,导入 CSS 文件: + +```css +@import 'bulma/css/bulma.css'; +``` + +### 使用 CDN + +使用 [jsDelivr](https://www.jsdelivr.com/package/npm/bulma) 导入 CSS 文件 + +```js + +``` + +### 本地 + +您可以从 GitHub 获得最新的 [Bulma](https://github.com/jgthms/bulma/blob/master/css/bulma.css) 版本,下载样式表文件到本地 + +## 屏幕尺寸 + +Bulma 是一个手机优先的框架,提供五个宽度断点,具有良好的自适应特性,可以随心所欲为不同设备设置不同样式。 + +``` + 768 1024 1216 1408 +' ' ' ' ' ' ' ' ' ' ' ' +<---------^------------^------------------^-------------^-------------> + mobile tablet desktop widescreen fullhd +``` + +## 网格体系 + +Bulma 的网格体系基于 Flex 布局,使用 `columns` 指定容器,使用 `column` 指定项目。 + +```html +
+
+
+
+
+
+
+``` + +## 修饰符 + +以下类定义**不同颜色**。 + +```css +.is-primary .is-link .is-info .is-success .is-warning .is-danger; +``` + +以下类定义**大小**。 + +```css +.is-small .is-normal .is-medium .is-large; +``` + +以下类定义**状态**。 + +```scss +.is-hovered +.is-outlined +.is-loading +.is-focused +.is-active +.is-static +``` + +完整的修饰类清单请看[官方文档](https://bulma.io/documentation/elements/button/)。 + +## 排版 + +以下类修改**字体大小**。 + +| `.is-size-1` | 3rem | +| ------------ | ------- | +| `.is-size-2` | 2.5rem | +| `.is-size-3` | 2rem | +| `.is-size-4` | 1.5rem | +| `.is-size-5` | 1.25rem | +| `.is-size-6` | 1rem | +| `.is-size-7` | 0.75rem | + +可以为不同设备指定不同的文字大小。 + +| `is-size-1-mobile` | 手机 | +| ------------------------- | ---------------- | +| `is-size-1-tablet` | 平板 | +| `is-size-1-touch` | 手机和平板 | +| `is-size-1-desktop` | 桌面、宽屏和高清 | +| `is-size-1-widescreen` | 宽屏和高清 | +| `size-1 is-size-1-fullhd` | 高清 | + +以下类**对齐**文本 + +| `.has-text-centered` | 使文本**成为中心** | +| --------------------- | ------------------ | +| `.has-text-justified` | 使文本**合理** | +| `.has-text-left`. | 使文本与**左**对齐 | +| `.has-text-right` | 使文本向**右**对齐 | + +以下类**转换**文本 + +| `.is-capitalized` | 将每个单词**的第一个字符**转换为**大写** | +| ----------------- | ---------------------------------------- | +| `.is-lowercase` | 将**所有**字符转换为**小写** | +| `.is-uppercase` | 将**所有**字符转换为**大写** | + +## 组件 + +Bulma 内置了 `Breadcrumb`、`Card`、`Menu` 等十种组件,使用超级简单、方便,你可以在这 👉 [components](https://bulma.io/documentation/components/) 查看这些组件。 + +以下以 Card 卡片为例: + +```html +
+
+
+ Lorem ipsum leo risus, porta ac consectetur ac, vestibulum at eros. +
+
+
+
+ Placeholder image +
+
+ +
+``` + +以上例子中,卡片内分为三部分:`card-content` 文本内容,`card-image` 图片容器,`card-footer` 脚部列表。 + +## WYSIWYG 内容 + +> WYSIWYG:所见即所得是一种系统。它使得用户在视图中所看到文档与该文档的最终产品具有相同的样式,也允许用户在视图中直接编辑文本、图形、或文档中的其他元素。 + +```html +
+ +

Heading

+

Paragraph

+ +
    +
  • Item 1
  • +
  • Item 2
  • +
+ +
+``` + +要为通常生成的 WYSIWYG 内容提供默认样式,请使用 `.content` 类。你可以在[Content](https://bulma.io/documentation/elements/content/)查看关于这类的内容。 + +## 定制 Bulma + +要想自定义 Bulma,您需要: + +- 安装 Bulma +- 有效的 Sass 设置 +- 创建自己的 `.scss` 和 `.sass` 文件 + +你可以通过 [node-sass](https://bulma.io/documentation/customize/with-node-sass)、[Sass CLI](https://bulma.io/documentation/customize/with-sass-cli)、[webpack](https://bulma.io/documentation/customize/with-webpack) 任何一种方法来实现,官网给出了详细的步骤,一步到位。下面我们简单的介绍下如何更改自定义样式。 + +先导入 Bulma [**初始变量**](https://bulma.io/documentation/customize/variables/),以如下为例: + +```scss +@import '../node_modules/bulma/bulma.sass'; // 该文件需要先引用 + +// 设置您需要更改颜色的变量 +$purple: #8a4d76; +$pink: #fa7c91; +$purple-color-1: $purple; // 派生变量 +``` + +上面代码中,预设的 `purple`、`pink` 和 `purple-color-1` 变量将被替换。 diff --git "a/CSS/CSS Reset \344\270\216 Sprites.md" "b/CSS/CSS Reset \344\270\216 Sprites.md" new file mode 100644 index 0000000..b65f9c4 --- /dev/null +++ "b/CSS/CSS Reset \344\270\216 Sprites.md" @@ -0,0 +1,94 @@ +# CSS Reset 与 Sprites + +总结起来就两段话: + +- Reset —— 重置浏览器默认属性。 +- Sprites —— 由多个小图片组成的图像。 + +## 为什么要初始化 CSS 样式 + +因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对 CSS 初始化往往会出现浏览器之间的页面显示差异。 + +当然,初始化样式会对 SEO 有一定的影响,但鱼和熊掌不可兼得,但力求影响最小的情况下初始化。 + +`*` 是最简单的初始化方法(不建议): + +```css +* { + padding: 0; + margin: 0; +} +``` + +但最好的做法是使用 CSS Reset 或 Normalize.css。 + +## CSS Reset 和 Normalize.css 有什么区别? + +[Normalize.css](https://necolas.github.io/normalize.css/) 是一种 CSS Reset 的替代方案,一种现代的 HTML 5 替代 CSS Reset 方法。 + +- **重置(Resetting)** — 重置意味着除去所有的浏览器默认样式。对于页面所有的元素,像 `margin`、`padding`、`font-size` 这些样式全部置成一样。你将必须重新定义各种元素的样式。 +- **标准化(Normalizing)** — 标准化没有去掉所有的默认样式,而是保留了有用的一部分,同时还纠正了一些常见错误。 + +另请:[Normalize 和 Reset 的区别](https://github.com/lio-zero/blog/blob/main/CSS/Normalize%20%E5%92%8C%20Reset%20%E7%9A%84%E5%8C%BA%E5%88%AB.md) + +### Normalize 的作用 + +以下是 Normalize 文档的作用描述: + +- 与许多 CSS Reset 不同,保留有用的默认值。 +- 规范化各种元素的样式。 +- 纠正错误和常见的浏览器不一致。 +- 通过细微的修改来提高可用性。 +- 使用详细注释解释代码的作用。 + +### 我们该如何去做选择呢? + +当需要实现非常个性化的网页设计时,我会选择重置的方式,因为我要写很多自定义的样式以满足设计需求,这时候就不再需要标准化的默认样式了。 + +## 什么是精灵图(CSS Sprites),其优缺点,以及如何实现? + +精灵图,也称雪碧图。精灵图是把多张小图片整合到一张图片中。它被运用在众多使用了很多小图标的网站上。 + +### 如何实现 + +首先,您需要一张精灵图,使用生成器将多张图片打包成一张精灵图。 + +> 推荐:[CSS Sprites Generator](https://www.toptal.com/developers/css/sprite-generator) + +接着,为需要使用到的图片设置 CSS 类,该类将使用 `background-image` 属性引入背景图片,`background-position` 属性进行背景定位,使用 `background-size` 属性进行缩放。 + +使用图片时,将相应的类添加到你的元素中。 + +### 优点 + +- 减少 HTTP 请求数(一张精灵图只需要一个请求),提高了页面加载速度。但是对于 HTTP/2 而言,加载多张图片不再是问题。 +- 提前加载资源,防止在需要时才在开始下载引发的问题,比如只出现在 `:hover` 伪类中的图片,不会出现闪烁。 +- 通过整合图片来减小图片的数量和体积。 +- 可以在一定程度上解决图片命名上的困扰。 +- 更换风格方便,只需在一张或几张图片上修改颜色或样式即可实现。 + +### 缺点 + +- 图片合并麻烦。 +- 维护比较麻烦,修改一个图片可能需要重新布局整个图片、样式。 + +### 扩展 + +- 在 HTTP/1.1 下,每个 TCP 连接最多允许一个请求 +- 使用 HTTP/1.1,现代的浏览器可以打开多个并行连接(2 到 8 之间),但是受到限制 +- 使用 HTTP/2,浏览器和服务器之间的所有请求都在单个 TCP 连接上多路复用 +- 这意味着可以减少打开和关闭多个连接的成本,从而可以更好地使用 TCP 连接并限制客户端和服务器之间的延迟影响。这样就可以在同一 TCP 连接上并行加载数十个图像 +- 尽管 HTTP/2 比 HTTP/1.1 改进了 50%,但在大多数情况下,sprites 的加载速度仍然比单个图像快。 +- 一种较新的技术是使用图标字体,它具有基于矢量的附加优点,因此在高分辨率(视网膜)屏幕上看起来更好。一些不错的图标字体是 [Awesome 字体](http://fortawesome.github.com/Font-Awesome/)和 [Foundation 图标](http://www.zurb.com/playground/foundation-icons) + +### 替代方案 + +- **Sprites 是栅格图像**,替代的方案通常是与其相关的,有 [SVG 图标](https://simurai.com/post/20251013889/svg-stacks)、[字体图标](https://css-tricks.com/flat-icons-icon-fonts/)、[字符编码](https://copypastecharacter.com/)等。 +- Sprites 就是为了减少服务器对图片的请求数,提高网站性能的一种手段。我们可以从解决图像请求的问题入手,也就是对图像进行懒加载 [lazyload](https://appelsiini.net/projects/lazyload/),还有渐进式[图像加载占位符](https://jmperezperez.com/medium-image-progressive-loading-placeholder/)。 + +### 提高效率实用工具 + +- [CSS Sprites Generato](https://www.toptal.com/developers/css/sprite-generator) 在线生成器 +- [SpriteCow](http://www.spritecow.com/) +- [SpriteMe](https://spriteme.org/) +- [Grunticon](https://github.com/filamentgroup/grunticon) 几年没维护了 diff --git "a/CSS/CSS background \345\261\236\346\200\247.md" "b/CSS/CSS background \345\261\236\346\200\247.md" new file mode 100644 index 0000000..cc03946 --- /dev/null +++ "b/CSS/CSS background \345\261\236\346\200\247.md" @@ -0,0 +1,329 @@ +# CSS background 属性 + +[`background`](https://developer.mozilla.org/en-US/docs/Web/CSS/background) 是一个 CSS 简写属性,用于设置任何元素的背景效果。它控制元素内容下方的绘制内容。 + +以下示例显示了可指定为元素创建任何背景效果的属性的完整列表: + +```css +header { + background: color image positionX positionY / size repeat attachment origin + clip; + background: plum /* color */ url('image/logo.jpg') /* image */ top center / + /* position */ 150px 150px /* size */ no-repeat /* repeat */ padding-box + /* origin */ content-box /* clip */ fixed; /* attachment */ +} +``` + +`background` 简写形式由八个属性组成。让我们深入了解它们每一个的用法。 + +## `background-color` + +CSS `background-color` 属性用于设置元素背景的颜色。如果图像需要时间加载,则可以将其与 `background-image` 属性组合作为备用选项。 + +`background-color` 值指定为颜色名称、十六进制值、RGB/RGBA 值或 HSL/HSLA 值。 + +### 默认值 + +`background-color` 的默认值是 `transparent` 关键字。 + +```css +header { + background-color: transparent; +} +``` + +### 用法 + +```css +/* 关键字值 */ +header { + background-color: red; +} + +/* 十六进制值 */ +header { + background-color: #bbff00; +} + +/* RGB 值 */ +header { + background-color: rgb(255, 255, 128); /* 完全不透明 */ +} +header { + background-color: rgba(117, 190, 218, 0.5); /* 50% 透明 */ +} + +/* HSL 值 */ +header { + background-color: hsl(50, 33%, 25%); /* 完全不透明 */ +} +header { + background-color: hsla(50, 33%, 25%, 0.75); /* 75% 透明 */ +} +``` + +## `background-image` + +`background-image`是一个 CSS 属性,用于将一个或多个图像设置为元素的背景。当指定多个图像时,它们显示为一个堆栈,一个在另一个之上。 + +### 默认值 + +`background-image` 的默认值是 `none`,这意味着不会显示任何图像。 + +```css +header { + background-image: none; +} +``` + +### 用法 + +此示例仅指定单个图像。 + +```css +header { + background-image: url('test.jpg'); +} +``` + +此示例将在 `second` 图像的顶部显示 `first` 图像。 + +```css +header { + background-image: url('image/first.jpg'), url('image/second.jpg'); +} +``` + +此示例指定 `banner` 图像上方的线性渐变。 + +```css +header { + background-image: linear-gradient( + to bottom, + rgba(255, 255, 0, 0.5), + rgba(0, 0, 255, 0.5) + ), url('image/banner.jpg'); +} +``` + +## `background-position` + +`background-position` 属性设置背景图像的起始位置。其值指定图像相对于元素边框的放置的坐标。 + +`background-position` 可以用关键字指定(`left`、`top`、`bottom`、`right`、`center`);百分比(`0%`,`25%` 等);或长度(`0cm`,`3px` 等)。这些值可以组合在一起。 + +### 默认值 + +`background-position` 的默认值是 `0% 0%`,表示元素边框的左上角。 + +```css +header { + background-position: 0% 0%; /* top left */ +} +``` + +### 用法 + +```css +header { + background-position: top; /* 顶部居中 */ + background-position: left; /* 左侧居中 */ + background-position: center; /* 水平垂直居中 */ + background-position: 20% 50%; /* 距左侧20% 距顶部50% */ + background-position: bottom 20px left 50px; /* 距底部20% 距左侧50% */ + background-position: left 2cm bottom 5cm; /* 距左侧2cm 距底部5cm */ +} +``` + +## `background-size` + +`background-size` 属性指定背景图像的大小。它定义了图像是被拉伸、以其原始大小显示还是填充整个可用空间。 + +值得注意的是,现在图像大小覆盖的空间将填充背景色。 + +### 关键字 + +`background-size` 可以使用关键字、百分比或长度指定。 + +- `cover`:将图像缩放到尽可能大的位置,但不会拉伸图像。它还可以垂直或水平裁剪图像以覆盖任何空白区域。 +- `contain`:将图像缩放到尽可能大的位置,但不会裁剪或拉伸图像。 +- `auto`:按相应方向缩放图像,使图像保持其原始比例 + +### 默认值 + +`background-size` 的默认值是 `auto`。 + +```css +header { + background-size: auto; +} +``` + +### 用法 + +```css +header { + background-size: auto /* 默认值 */ | cover /* 拉伸以填充元素的框 */ | contain; /* 缩放图像而不剪切/剪切。图像可以重复以填充元素的框 */ +} + +/* 按 20% 宽度缩放图像,并自动调整高度。图像可以重复以填充元素的框 */ +header { + background-size: 20% auto; +} + +/* 按 3em 宽和 25% 高缩放图像。图像可以重复以填充元素的框 */ +header { + background-size: 3em 25%; +} + +/* 可以为多个背景指定更多值 */ +header { + background-size: 50%, 25%, 60%; +} +``` + +## `background-repeat` + +`background-repeat` 属性定义背景图像的重复方式。背景图像可以沿着水平、垂直、水平垂直重复,或者根本不重复。 + +由于默认情况下图像被剪裁为其元素的大小,因此也可以使用 `background-repeat` 属性缩放图像以适应或填充元素的区域。 + +### 关键字 + +`background-repeat` 属性是使用关键字值指定的。 + +- `repeat`:重复图像以覆盖整个背景 +- `no-repeat`: 不会重复图片 +- `space`:重复图像而不剪裁,并在重复图像之间均匀分布空白 +- `round`:重复图像,并填充重复图像之间的空白 +- `repeat-x`:仅沿 x 轴重复图像 +- `repeat-y`:仅沿 y 轴重复图像 + +### 默认值 + +`background-repeat` 的默认值就是 `repeat`,它会重复图像,直到图像填充整个元素背景。 + +```css +header { + background-repeat: repeat; +} +``` + +### 用法 + +```css +header { + background-repeat: repeat-x /* 相当于 repeat no-repeat */ | repeat-y + /* 相当于 no-repeat repeat */ | repeat /* 相当于 repeat repeat */ | space + /* 相当于 space space */ | round /* 相当于 round round */ | no-repeat; /* 相当于 no-repeat no-repeat */ +} +``` + +## `background-attachment` + +`background-attachment` 属性指定背景图像应可滚动还是固定到视口。 + +### 关键字 + +`background-attachment` 属性仅使用关键字指定。 + +- `scroll`:将背景图像固定到其元素。不滚动包含内容的背景图像 +- `fixed`:将背景图像固定到视口。即使内容可滚动,背景图像也不会滚动 +- `local`:修复相对于元素内容的背景图像,从而允许背景图像随着内容滚动而滚动 + +### 默认值 + +`background-attachment` 的默认值为 `scroll`。 + +```css +header { + background-attachment: scroll; +} +``` + +### 用法 + +```css +header { + background-attachment: scroll + /* 将图像固定到元素(仅当元素正在滚动而不是元素的内容时才能滚动) */ | fixed + /* 将图像固定到视口 */ | local; /* 滚动包含内容的图像 */ +} + +/* 在多个图像上,我们可以指定双值 */ +header { + background-image: url('pic1.gif'), url('pic2.gif'); + background-attachment: fixed, scroll; +} +``` + +## `background-origin` + +`background-origin` 属性指定在何处绘制背景图像。使用 `content-box` 值将跨越整个元素,在边框内使用 `border-box` 值或在填充内使用 `padding-box` 值。 + +**请注意**,当 `background-attachment` 设置为 `fixed` 时,`background-origin` 将被忽略,并且 `background-origin` 与 `background-clip` 相同,只是它调整背景的大小而不是剪辑。 + +### 关键字 + +`background-origin` 属性是使用关键字值指定的。 + +- `content-box`:相对于内容区域定位背景 +- `border-box`:相对于边框区域定位背景 +- `padding-box`:相对于填充区域定位背景 + +### 默认值 + +`background-origin` 的默认值是 `padding-box` 关键字。 + +```css +header { + background-origin: padding-box; +} +``` + +### 用法 + +```css +header { + background-origin: border-box | padding-box | content-box; +} + +/* 我们可以为多个图像指定双值 */ +header { + background-image: url('logo.jpg'), url('banner.png'); + background-origin: content-box, padding-box; +} +``` + +## `background-clip` + +`background-clip` 属性用于设置元素的背景(背景图片或颜色)是否延伸到边框、内边距盒子、内容盒子下面。 + +> **请注意**,此属性仅在指定了背景图像或背景颜色时才具有实际效果;否则,它将仅在边界上具有视觉效果。 + +### 关键字 + +`background-clip` 属性是使用关键字值指定的。 + +- `border-box`:默认值,将背景延伸到元素的边框区域外沿 +- `content-box`:将背景裁剪至内容区域外沿。 +- `padding-box`:将背景延伸到元素的填充区域外沿 +- `text`:将背景被裁剪成文字的前景色。(**实验值**) + +### 默认值 + +`background-clip` 的默认值是 `border-box` 关键字。 + +```css +header { + background-clip: border-box; +} +``` + +### 用法 + +```css +header { + background-clip: border-box | padding-box | content-box; +} +``` diff --git "a/CSS/CSS content-visibility \345\261\236\346\200\247 \342\200\224 \346\216\250\350\277\237\345\206\205\345\256\271\346\270\262\346\237\223.md" "b/CSS/CSS content-visibility \345\261\236\346\200\247 \342\200\224 \346\216\250\350\277\237\345\206\205\345\256\271\346\270\262\346\237\223.md" new file mode 100644 index 0000000..4b4417a --- /dev/null +++ "b/CSS/CSS content-visibility \345\261\236\346\200\247 \342\200\224 \346\216\250\350\277\237\345\206\205\345\256\271\346\270\262\346\237\223.md" @@ -0,0 +1,40 @@ +# CSS content-visibility 属性 — 推迟内容渲染 + +[`content-visibility`](https://web.dev/content-visibility/) 是新的 CSS 属性,可以提高页面加载性能。对于具有大量内容块、图像和视频丰富的复杂布局,解码数据和渲染像素可能是一项非常昂贵的操作,尤其是在低端设备上。 + +使用 `content visibility: auto`,我们可以在容器位于视口之外时提示浏览器跳过子对象的布局。 + +例如,您可以跳过在初始加载时渲染 `footer`: + +```css +footer { + content-visibility: auto; + /* 1000px 是尚未渲染的部分的估计高度。 */ + contain-intrinsic-size: 1000px; +} +``` + +它是新的属性,仅支持 Chrome 85+、Edge 85+ 和 Opera 71+ 等少部分主流浏览器。 + +![2022/2/5:content-visibility 的支持情況](https://upload-images.jianshu.io/upload_images/18281896-ac3fe1a690335e52.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +如果您需要声明当前元素和它的内容尽可能的独立于 DOM 树的其他部分,可以使用 [CSS contain](https://developers.google.com/web/updates/2016/06/css-containment) 属性。这使得浏览器在重新计算布局、样式、绘图、大小或这四项的组合时,只影响到有限的 DOM 区域,而不是整个页面,可以有效改善性能。 + +```css +.ele { + contain: none | strict | content | [ size | layout | style | paint ]; +} +``` + +> **注意**:[`content-visibility: auto` 的行为类似于 `overflow: hidden;`](https://www.terluinwebdesign.nl/en/css/calculating-contain-intrinsic-size-for-content-visibility/),但您可以通过应用 `padding-left/right` 来修复它,而不是使用默认的 `margin: 0 auto;` 以及声明的宽度。`padding` 基本上允许元素溢出 `content` 并进入 `padding`,而不会将盒模型作为一个整体离开并被切断。 + +另外,请记住,当新内容最终渲染时,您可能会引入一些 [CLS](https://web.dev/cls/)(Cumulative Layout Shift,累积布局偏移),因此最好使用具有适当大小占位符的 `contain-intrinsic-size`。 + +[一个关于 Content-visibility 的示例](https://codepen.io/vmpstr/pen/xxZoyMb)。 + +## 更多资源 + +- [content-visibility](https://css-tricks.com/almanac/properties/c/content-visibility/) +- [Calculating 'contain-intrinsic-size' for 'content-visibility'](https://www.terluinwebdesign.nl/en/css/calculating-contain-intrinsic-size-for-content-visibility/) +- [使用 CSS3 will-change 提高页面滚动、动画等渲染性能](https://www.zhangxinxu.com/wordpress/2015/11/css3-will-change-improve-paint/) +- [content-visibility——只需一行 CSS 代码,让长列表网页的渲染性能提升几倍以上!](https://juejin.cn/post/6908521872577527822#heading-1) diff --git "a/CSS/CSS outline \345\261\236\346\200\247.md" "b/CSS/CSS outline \345\261\236\346\200\247.md" new file mode 100644 index 0000000..8b065ab --- /dev/null +++ "b/CSS/CSS outline \345\261\236\346\200\247.md" @@ -0,0 +1,93 @@ +# CSS outline 属性 + +CSS [`outline`](https://developer.mozilla.org/en-US/docs/Web/CSS/outline)(轮廓)是一个简写属性,用于围绕元素外部绘制一条线。它与 `a:focus` 选择器结合使用特别有用,可以更加强调链接或其他元素。 + +`outline` 与 `border` 相似,不同之处在于 `outline` 在整个元素周围画了一条线;它不能像 `border` 那样,指定在元素的一个面上设置轮廓,也就是不能单独设置顶部轮廓、右侧轮廓、底部轮廓或左侧轮廓。 + +## 语法 + +```css +outline: width | style | color; +``` + +`outline` 简写属性可以用一个、两个或三个值声明,并且它们的顺序可以任意更换。例如: + +```css +outline: solid; /* 这仅指定样式值 */ + +outline: dashed #eee; /* 这将指定颜色值和样式值 */ + +outline: thick inset; /* 这将指定宽度值和样式值 */ + +outline: 1px solid plum; /* 这将指定所有 3 个值 */ +``` + +![outline](https://upload-images.jianshu.io/upload_images/18281896-4c29ac0c5fda6f5b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +这里需要注意两点: + +- 当仅指定一个或两个值时,其他值将解析为其默认值。`outline` 只需设置其 `style` 值即可工作。 +- 如果未定义样式,许多元素的轮廓将不可见。这是因为样式默认为 `none`。一个例外是 `input` 元素,它们由浏览器赋予默认样式。 + +## 属性 + +`outline` 属性是由三个单独属性组成的缩写,用于定义轮廓的颜色、宽度和样式。我们将在下面逐一探讨。 + +### `outline-width` + +`outline-width` 定义要绘制的线的厚度。其值可以是任意长度值,也可以是以下任意关键字: + +- `thin` +- `medium`(默认值) +- `thick` + +```css +outline-width: 2 (px, em, rem) | thin | medium | thick; +``` + +### `outline-style` + +`outline-style` 定义要绘制的线的类型。它的值可以是以下任何关键字: + +- `auto` +- `dotted` +- `dashed` +- `solid` +- `double` +- `groove` +- `ridge` +- `inset` +- `outset` +- `none`(默认值,没有轮廓) + +```css +outline-style: auto | dotted | dashed | solid | double | groove | ridge | inset + | outset; +``` + +### `outline-color` + +`outline-color` 用于设置一个元素轮廓的颜色。它可以通过关键字、十六进制值、RGB/RGBA 值和 HSL/HSLA 值来指定。 + +如果[浏览器支持](https://caniuse.com/?search=outline-color),其默认值为 `invert`;否则,其默认值为 [`currentColor`](https://github.com/lio-zero/css-tricks#%E4%BD%BF%E7%94%A8-currentcolor-%E5%85%B3%E9%94%AE%E5%AD%97%E9%87%8D%E7%94%A8%E5%BD%93%E5%89%8D%E9%A2%9C%E8%89%B2)。 + +```css +outline-color: currentColor | red | #eee | rgb(255, 255, 255) | hsl(0, 0, 0); +``` + +## 有趣的用法 + +尝试打开任何网站上的控制台并运行以下内容: + +```js +document.head.insertAdjacentHTML( + 'beforeend', + '' +) +``` + +你们会看到很多网站都是这样的结构: + +![outline](https://upload-images.jianshu.io/upload_images/18281896-707c9f70b633ab55.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +默认情况下,`outline` 用于 `:focus` 样式。但请记住,如果删除轮廓样式,例如:`a:focus { outline: 0; }`,您需要使用其他视觉上不同的样式将它们添加回来。 diff --git "a/CSS/CSS scroll-behavior\345\261\236\346\200\247 \342\200\224 \347\272\257 CSS \345\271\263\346\273\221\346\273\232\345\212\250.md" "b/CSS/CSS scroll-behavior\345\261\236\346\200\247 \342\200\224 \347\272\257 CSS \345\271\263\346\273\221\346\273\232\345\212\250.md" new file mode 100644 index 0000000..e717a9e --- /dev/null +++ "b/CSS/CSS scroll-behavior\345\261\236\346\200\247 \342\200\224 \347\272\257 CSS \345\271\263\346\273\221\346\273\232\345\212\250.md" @@ -0,0 +1,50 @@ +# CSS scroll-behavior 属性 — 纯 CSS 平滑滚动 + +CSS 中的 `scroll-behavior` 属性是一个非常新的属性。定义要求 `scroll-behavior`(尤其是在选择锚链接时)具有平滑的过渡动画外观,而不是默认的、更刺眼的即时跳转。 + +```css +html { + scroll-behavior: auto | smooth; +} +``` + +`scroll-behavior` 属性接受两个值,将切换打开和关闭的平滑滚动功能。 + +- `auto`(默认):该值允许滚动框中的元素之间突然跳转。 +- `smooth`:顾名思义,该值是滚动框内元素之间的平滑的过渡动画。 + +它是较新的属性,支持 Chrome 61+、Firefox 36+ 和 Opera 48+ 等主流浏览器。 + +![2022/2/5:scroll-behavior 支持情况](https://upload-images.jianshu.io/upload_images/18281896-4b757024f53d4502.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +## 示例:返回顶部 + +默认情况下,通过单击锚链接定位页面中的元素,浏览器将直接跳转到目标。 + +在不使用任何 JavaScript 的情况下,我们可以使用简单的 CSS `scroll-behavior` 属性平滑地滚动到给定的元素。 + +这里给出一个平滑滚动到顶部的示例,在 `` 元素上提供以 ID 为目标的链接: + +```html + + + 跳转到页面顶部 + + +``` + +将 `scroll-behavior` 属性设置为 `html` 元素可实现整个页面的平滑滚动效果: + +```css +html { + scroll-behavior: smooth; +} +``` + +> [查看效果](https://codepen.io/lio-zero/pen/qBRxNQL) + +## 更多资料 + +- [scroll-behavior](https://css-tricks.com/almanac/properties/s/scroll-behavior/) +- [Downsides of Smooth Scrolling](https://css-tricks.com/downsides-of-smooth-scrolling/) +- [滚动到页面顶部的多种实现](https://github.com/lio-zero/blog/blob/main/JavaScript/%E6%BB%9A%E5%8A%A8%E5%88%B0%E9%A1%B5%E9%9D%A2%E9%A1%B6%E9%83%A8%E7%9A%84%E5%A4%9A%E7%A7%8D%E5%AE%9E%E7%8E%B0.md) diff --git "a/CSS/CSS vertical-align \345\261\236\346\200\247.md" "b/CSS/CSS vertical-align \345\261\236\346\200\247.md" new file mode 100644 index 0000000..f8ee474 --- /dev/null +++ "b/CSS/CSS vertical-align \345\261\236\346\200\247.md" @@ -0,0 +1,110 @@ +# CSS vertical-align 属性 + +CSS [`vertical-align`](https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align) 属性控制在一行上相邻设置的元素如何对齐。 + +```css +img { + vertical-align: middle; +} +``` + +> **注意**:为了使其正常工作,我们需要沿基线设置元素。如:`inline` 内联元素(例如 ``,``)或 `inline-block` 内联块(例如,由 `display` 属性设置)元素。`vertical-align` 属性也适用于 `table-cell` 元素。 + +## 语法 + +```css +elem { + vertical-align: baseline | top | bottom | middle | text-top | text-bottom | + sub | super | length units; +} +``` + +## 关键字 + +- `vertical-align` — 默认值。顾名思义,它将元素与父元素的基线对齐。 +- `top` — 将元素与一行中最高元素的顶部对齐。 +- `bottom` — 将元素与底部对齐,元素处于同一级别。 +- `middle` — 将元素与其父元素的中心对齐。 +- `text-top` — 使用其父元素行中最高字体的顶部对齐元素。 +- `text-bottom` — 使用其父元素行中最高字体的底部对齐元素。 +- `sub` — 将元素对齐到其父元素的基线下标。它的行为更像 `` 标签。 +- `super` — 将元素与父元素的基线上标对齐。它的行为更像 `` 标签。 + +## 长度和百分比值 + +将元素与给定单位对齐。正数将使元素与基线上方对齐,负值将使元素与基线下方对齐。 + +这些值可以是任意长度单位:`px`,`em`,`%`,等。 + +```css +img { + vertical-align: 10px; +} + +img { + vertical-align: 50%; +} + +img { + vertical-align: 3em; +} +``` + +## 全局值 + +`initial` — 将元素的对齐方式设置为其默认值,即 `baseline`。 + +```css +img { + vertical-align: initial; +} +``` + +`inherit` — 将元素的对齐方式设置为其父元素的值。 + +```css +img { + vertical-align: inherit; +} +``` + +## 例子 + +### 表格 + +`vertical-align` 属性可以直接应用用于表格单元格,可以将对齐单元格内的内容。重要的一点是,它能很好的兼容浏览器在显示效果上的一致性。 + +```css +td { + height: 40px; + vertical-align: middle; +} +``` + +效果如下: + +![vertical-align](https://upload-images.jianshu.io/upload_images/18281896-61ce21993fb07bdb.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +### 垂直居中 + +`vertical-align` 属性不允许您在另一个元素中 “垂直居中” 一个元素。我们更多的会使用 **Flexbox** 来做垂直居中。 + +但是,您可能不知道,有一个 **ghost** 技巧可以帮助您垂直居中一个元素。 + +```css +p { + border: 1px solid plum; + display: table; + height: 100px; + width: 100px; +} + +span { + display: table-cell; + vertical-align: middle; +} +``` + +效果如下: + +![vertical-align](https://upload-images.jianshu.io/upload_images/18281896-a45337c39b47f83e.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) diff --git "a/CSS/CSS will-change \345\261\236\346\200\247 \342\200\224 \344\274\230\345\214\226\346\270\262\346\237\223\346\200\247\350\203\275.md" "b/CSS/CSS will-change \345\261\236\346\200\247 \342\200\224 \344\274\230\345\214\226\346\270\262\346\237\223\346\200\247\350\203\275.md" new file mode 100644 index 0000000..c847828 --- /dev/null +++ "b/CSS/CSS will-change \345\261\236\346\200\247 \342\200\224 \344\274\230\345\214\226\346\270\262\346\237\223\346\200\247\350\203\275.md" @@ -0,0 +1,36 @@ +# CSS will-change 属性 — 优化渲染性能 + +> **[`will-change`](https://developer.mozilla.org/zh-CN/docs/Web/CSS/will-change) 属性可以开启 GPU 硬件加速以提升/优化网站动画渲染性能。** + +`will-change` 通过告知浏览器该元素会有哪些变化,使浏览器提前做好优化准备,增强页面渲染性能。 + +语法: + +```css +will-change: = scroll-position | contents | ; +``` + +`will-change` 属性的取值: + +- `auto` — 应用标准浏览器优化。 +- `scroll-position` — 表示元素的滚动位置将在不久的将来某个时候设置动画,以便浏览器准备在元素的滚动窗口中看不到的内容。 +- `contents` — 表示希望在不久后改变元素内容中的某些东西,或者使它们产生动画。 +- `` — 任何用户定义的属性,比如 `transform` 或 `opacity`,表示希望在不久后改变指定的属性名或者使之产生动画, + +> **注意**:不要将 `will-change` 应用到太多元素上,如果过度使用的话,可能导致页面响应缓慢或消耗大量资源。详细内容查看 [will-change](https://developer.mozilla.org/zh-CN/docs/Web/CSS/will-change)。 + +以下是 `will-change` 的支持情況: + +![2022/2/5:will-change 支持情況](https://upload-images.jianshu.io/upload_images/18281896-bcaa354083f45bef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +[一个关于 will-change 的示例](https://codepen.io/nchan0154/pen/abVNYNo) + +## 更多资源 + +- [will-change](https://css-tricks.com/almanac/properties/w/will-change/) +- [Fix scrolling performance with CSS will-change property](https://www.fourkitchens.com/blog/article/fix-scrolling-performance-css-will-change-property/) +- [My white whale: A use case for will-change](https://www.nicchan.me/blog/a-use-case-for-will-change/) +- [Everything You Need to Know About the CSS will-change Property](https://dev.opera.com/articles/css-will-change-property/) +- [An Introduction to the CSS will-change Property](https://www.sitepoint.com/introduction-css-will-change-property/) +- [使用 CSS3 will-change 提高页面滚动、动画等渲染性能](https://www.zhangxinxu.com/wordpress/2015/11/css3-will-change-improve-paint/) +- [How to create high-performance CSS animations](https://web.dev/animations-guide/) diff --git "a/CSS/CSS \345\215\225\344\275\215\345\217\212\345\205\266\351\234\200\350\246\201\346\263\250\346\204\217\347\232\204\345\234\260\346\226\271.md" "b/CSS/CSS \345\215\225\344\275\215\345\217\212\345\205\266\351\234\200\350\246\201\346\263\250\346\204\217\347\232\204\345\234\260\346\226\271.md" new file mode 100644 index 0000000..22fe510 --- /dev/null +++ "b/CSS/CSS \345\215\225\344\275\215\345\217\212\345\205\266\351\234\200\350\246\201\346\263\250\346\204\217\347\232\204\345\234\260\346\226\271.md" @@ -0,0 +1,33 @@ +# CSS 单位及其需要注意的地方 + +- `px`(Pixel):绝对长度单位,绝对像素值,它取决于显示器的分辨率。一旦分辨率确定,设置为 `px` 的尺寸就成为固定尺寸,不会自动缩放。(1px = 1/96 英寸) +- `em`:相对长度单位,相对于父元素的 `font-size`。如父元素未设置 `font-size`,则相对于浏览器的默认字体尺寸(`1em = 16px`,**注意**:浏览器的默认字体大小可以更改)。通常的做法是将默认的正文字体大小设置为 62.5%(等于 10px)。 +- `rem`(root em):CSS3 新增的一个相对单位。相对于根元素的 `font-size`,其元素的大小都与根元素换算(默认浏览器的大小 `16px`)。 +- `%`:相对于父元素。例如:`font-size: 100%` 和 `font-size: 1em` 一样,它们都表示字体大小是默认(继承自父元素)字体大小的 2 倍;`line-height: 200%` 表示行高是自己字体大小的 2 倍。 +- `vw`:相对于视口的宽度,`1vw = 1% * viewport width`(视口宽度) +- `vh`:相对于视口的高度,`1vh = 1% * viewport height`(视口高度) +- `vmin`:相对于视口的较小尺寸(`vw` 和 `vh` 中的最小值),`1vmin = min`(`1vh`,`1vw`) +- `vmax`:相对于视口的较大尺寸(`vw` 和 `vh` 中的最大值),`1vmax = max`(`1vh`,`1vw`) +- `ch`:相对于元素字体的字形 `0` 的宽度,也就是 `1ch = 0`(一个 0 的宽度),`3ch = 000`(三个 0 的宽度)。允许完美的元素 + 文本缩放。 +- `in`(英寸):`1in` = `2.54cm`=`96px` +- `pc`(`Picas`,皮卡):`1pc = 1in / 6 = 16px`,也就是大约 `6pt`,`1/6` 英寸,也就是 `1pc = 12pt = 1/6in`。 +- `pt`(`Point`,点):`1pt = 1in / 72 = 1.333px`(大约),它是物理长度单位,相当于 `1/72` 英寸。通常在印刷中使用。(`1pt = 1/72in`) +- `cm`(厘米): `1cm = 96px / 2.54 = 37.8px`(大约) +- `mm`(毫米):`1mm = 1cm / 10 = 3.78px`(大约) + +## 注意点 + +- `px` 和 `em` 都是长度单位,区别是 `px` 的值是固定的,计算比较容易。`em` 得值不是固定的,并且 `em` 会继承父级元素的字体大小。 +- 浏览器的默认字体大小都是 `16px`。所以未经调整的浏览器都符合: `1em = 16px`。那么 `12px = 0.75em`,`10px = 0.625em`。通常,我们会将浏览器的默认字体设置为 `62.5%`,此时 `1rem = 16px * 62.5% = 10px`(所以 `12px = 1.2rem`);(1:10 的比例更好换算) +- `%` 与 `em` 一样,都是级联的,意思是父元素的的字体大小会影响到子元素。 +- `em` 和 `rem` 单位可用于创建完美的可扩展布局,兼容多设备的不二之选! +- 相对长度:`em`、`rem`、`vw`、`vh`、`vmin`、`vmax`、`%`、`ch`。其相对于另一个长度属性,在不同设备之间缩放表现得更好。 +- 绝对长度:`px`、`cm`、`mm`、`pt`、`pc`、`in`。其尺寸都是固定的,不同设备的尺寸不同,变化跨度大,所以不建议在屏幕上使用绝对长度单位。但是,如果已知输出介质,则可以使用它们,例如用于打印布局(print layout)。 +- 《CSS 权威指南》指出:`px` 是相对长度单位,而《The Lengths of CSS》指出:`px` 是绝对长度单位。权威文档 MDN 上将 `px` 定义为了绝对单位。(本文将其归为绝对单位) +- **视口(Viewport)**:在桌面端,视口指的是浏览器内部的可视区域大小,即 `window.innerWidth/window.innerHeight` 大小,不包含任务栏、标题栏以及底部工具栏的浏览器区域大小;而在移动端较为复杂,它涉及到三个视口:分别是 `Layout Viewport`(布局视口)、`Visual Viewport`(视觉视口)、`Ideal Viewport`(理想视口)。 而视口单位中的**视口**,在桌面端,毫无疑问指的就是浏览器的可视区域;但是在移动端,它指的则是三个 Viewport 中的 `Layout Viewport`。 + +CSS 中的四个视口单位分部是 `vw`、`vh`、`vmin` 和 `vmax`。以下是它们的兼容情况: + +![vw,vh,vmin,vmax](https://upload-images.jianshu.io/upload_images/18281896-49bb83a48c764b3a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +**扩展**:如果您开发过微信小程序,你可能还使用 `rpx`,它是微信小程序独有的、解决屏幕自适应的尺寸单位。 diff --git "a/CSS/CSS \345\256\236\347\216\260\346\226\207\346\234\254\346\272\242\345\207\272\347\234\201\347\225\245\346\225\210\346\236\234.md" "b/CSS/CSS \345\256\236\347\216\260\346\226\207\346\234\254\346\272\242\345\207\272\347\234\201\347\225\245\346\225\210\346\236\234.md" new file mode 100644 index 0000000..cc89bb9 --- /dev/null +++ "b/CSS/CSS \345\256\236\347\216\260\346\226\207\346\234\254\346\272\242\345\207\272\347\234\201\347\225\245\346\225\210\346\236\234.md" @@ -0,0 +1,38 @@ +# CSS 实现文本溢出省略效果 + +## 单行文本溢出 + +以下是截断单行长文本的 CSS 片段: + +```css +.truncate { + width: 250px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +``` + +- `overflow: hidden` — 文字长度超出限定宽度,则隐藏超出的内容 +- `text-overflow: ellipsis` — 规定当文本溢出时,显示省略符号来代表被修剪的文本 +- `white-space: nowrap` — 设置文字在一行显示,不能换行 + +## 多行文本溢出 + +使用 `-webkit-line-clamp` 可以设置多行超出显示省略号,下面的 CSS 声明将行数限制为 2: + +```css +.truncate { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; +} +``` + +> **注意**:`-webkit-line-clamp` 属性仅在具有 `display: -webkit-box` 和 `-webkit-box-orient: vertical` 声明时有效。 + +## 更多资料 + +[Line Clampin (Truncating Multiple Line Text)](https://css-tricks.com/line-clampin/) 给出了更多灵活的文本溢出方案。 diff --git "a/CSS/CSS \347\233\222\346\250\241\345\236\213.md" "b/CSS/CSS \347\233\222\346\250\241\345\236\213.md" new file mode 100644 index 0000000..ca04a61 --- /dev/null +++ "b/CSS/CSS \347\233\222\346\250\241\345\236\213.md" @@ -0,0 +1,66 @@ +# CSS 盒模型 + +CSS 是关于盒子的。页面上显示的所有内容都有一个框,[**盒模型**(box model)](https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/The_box_model)描述了如何计算该框的大小 —— 考虑了边距(`margin`)、边框(`border`)、填充(`padding`)和内容(`content`)。 + +以下图片说明了盒模型(Box Model)的层级分部: + +![CSS 盒模型](https://upload-images.jianshu.io/upload_images/18281896-1d9164962395e977.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +由内到外,分别是: + +- **`content`(内容)** — 盒子的内容,其中显示文本和图像 +- **`padding`(填充)** — 围绕内容的透明区域(即边框和内容之间的空间) +- **`border`(边框)** — 围绕在内边距和内容外的边框。 +- **`margin`(边界)** — 边距周围的透明区域(即边距与任何相邻元素之间的空间) + +它们解释了元素的大小,对应着相应的 CSS 属性,除了 content(CSS 属性 `width/height`)。 + +## IE 盒模型和 W3C 盒模型 + +这里需要介绍一下 IE 盒模型和 W3C 盒模型的区别。 + +盒模型分为两类:**W3C 标准盒模型和 IE 盒模型**。 + +- W3C 标准盒模型 — 元素的宽度(`width`)和高度(`height`)只包含内容(`content`)。而 `width`、`padding` 和 `border` 一起决定了整个盒子的大小。 +- IE 盒模型 — 元素的宽度(`width`)和高度(`height`)包含了 `content`、`padding` 和 `border`。整个盒子的大小由 `width/height` 决定。 + +```css +.box { + width: 200px; + padding: 10px; + border: 5px solid plum; + margin: 0; +} +``` + +以上元素的宽度在 IE 盒模型和 W3C 盒模型中是不同的: + +- W3C 盒模型 — `200px + 10px + 10px + 5px + 5px = 230px`。 +- IE 盒模型 — `200px` + +标准 CSS 盒模型采用给定元素的宽度,然后在该宽度上添加 `padding` 和 `border`,这意味着元素占用的空间大于给定的宽度。 + +## 如何进行不同盒模型的切换? + +CSS3 `box-sizing` 属性提供给我们切换盒模型的权利,它有如下三个值: + +- `content-box` — 默认的标准(W3C)盒模型元素效果 +- `border-box` — 触发怪异(IE)盒模型元素的效果 +- `inherit` — 继承父元素 `box-sizing` 属性的值 + +```css +.box { + box-sizing: content-box | border-box | inherit; +} +``` + +> **注意**:到 IE8+ 才支持使用 `box-sizing` 进行盒模型切换。 + +我们可能不明确或者总是去计算加上 `padding` 和 `border` 才能获取元素的实际大小,这变的很麻烦。这时,我们可以使用 `box-sizing: border-box` 在设置有 `padding` 和 `border` 值时不把元素的宽度/高度撑开。 + +## 更多资料 + +- [MDN Docs:盒模型](https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/The_box_model) — 完整的介绍 +- [CSS Box Model Module Level 3](https://www.w3.org/TR/css-box-3/) +- [BFC 及其应用](https://github.com/lio-zero/blog/blob/main/CSS/BFC%20%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8.md) +- [CSS 盒模型之内边距、边框、外边距 十九问 (持续更新)](https://juejin.cn/post/6880111680153059341) diff --git "a/CSS/CSS \347\273\247\346\211\277\343\200\201\347\272\247\350\201\224\345\222\214\347\211\271\345\274\202\346\200\247.md" "b/CSS/CSS \347\273\247\346\211\277\343\200\201\347\272\247\350\201\224\345\222\214\347\211\271\345\274\202\346\200\247.md" new file mode 100644 index 0000000..003afa8 --- /dev/null +++ "b/CSS/CSS \347\273\247\346\211\277\343\200\201\347\272\247\350\201\224\345\222\214\347\211\271\345\274\202\346\200\247.md" @@ -0,0 +1,394 @@ +# CSS 继承、级联和特异性 + +如果你想更好的掌握 CSS,CSS 的特异性是一个重要的话题。应用于 CSS 选择器的一组规则决定了应用于元素的样式。为了更好地理解这一点,我们必须了解一个相关的主题 —— CSS 中的[**级联和继承**](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance)。 + +## CSS 的级联特性 + +CSS **层叠/级联样式表(cascade Stylesheets)**—— 简单的说,CSS 规则的顺序很重要;当应用两条同级别的规则到一个元素的时候,写在后面的就是实际使用的规则。我们来看一个例子,理解这一点。 +我们将在一个元素中应用两个类,并为每个类提供一个不同的 `color`。 + +```html +

I'm Superman

+``` + +同时应用如下两个 CSS 类: + +```css +.color-pink { + color: pink; +} + +.color-plum { + color: plum; +} +``` + +效果如下: + +![color-plum](https://upload-images.jianshu.io/upload_images/18281896-066db08968c00314.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +**注意**,样式表中最后的 `color-plum` 将应用于元素。现在,您可能希望 CSS 总是这样将样式应用于元素,但情况并非总是如此。 + +```html +

I'm Superman

+``` + +CSS 如下: + +```css +#paragraph { + color: pink; +} + +.color-plum { + color: plum; +} +``` + +您希望将哪种样式应用于元素?`#paragraph` 还是 `.color-plum`? + +效果如下: + +![paragraph](https://upload-images.jianshu.io/upload_images/18281896-74f8aec7533425d0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +**注意**,应用了第一个。`#paragraph` 是一个 ID 选择器,而 `.color-plum` 是一个类选择器。这是因为级联具有特异性,来确定哪些值应用于元素。那么,CSS 的特异性是什么呢? + +## CSS 继承的特性 + +[继承](https://developer.mozilla.org/en-US/docs/Web/CSS/inheritance)定义了哪些属性由它们所应用于的元素的子元素继承。 +继承也需要在上下文中去理解 —— 一些设置在父元素上的 CSS 属性是可以被子元素继承的,有些则不能。 + +```html +

+ I'm Superman +

+``` + +CSS 如下: + +```css +p { + color: plum; + font-size: 2rem; + border: medium solid; +} +``` + +效果如下: + +![继承](https://upload-images.jianshu.io/upload_images/18281896-4111dc7006a56929.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +可以看到,`` 继承了 `color`,但是没继承 `border`,因为 `border` 就是一个典型的非继承属性, + +这里顺带讲一下一些可以控制继承的一些属性。 + +CSS 为控制继承提供了四个特殊的通用属性值。每个 CSS 属性都接收这些值。 + +- `inherit` 设置该属性会使子元素属性和父元素相同。实际上,就是 "开启继承". +- `initial` 设置属性值和浏览器默认样式相同。如果浏览器默认样式中未设置且该属性是自然继承的,那么会设置为 `inherit` 。 +- `unset` 将属性重置为自然值,也就是如果属性是自然继承那么就是 `inherit`,否则和 `initial`一样 +- `revert` 只有很少的浏览器支持。 + +```html +
+

I'm Superman

+
+ +
+

I'm Superman

+
+``` + +```css +h2 { + color: plum; +} + +.extra h2 { + color: inherit; +} +``` + +![inherit](https://upload-images.jianshu.io/upload_images/18281896-120ddf5b10264ca3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +可以看到,我们将 `

` 的字体颜色设置为 `color: plum`,但是第二个 `

` 确没有应用该颜色。原因是,我们在第二个 h2 中的 `color` 属性值使用了 `inherit`,该属性将继承父元素的值,没有设置将应用默认值。 + +## CSS 哪些属性可以继承?哪些属性不可以继承? + +- 可以继承的样式:`font-size`、`font-family`、`color`、`list-style`、`cursor` 等。 +- 不可继承的样式:`width`、`height`、`border`、`padding`、`margin`、`background` 等。 + +## CSS 特异性解释 + +> 根据 MDN,浏览器通过[**特异性(优先级)**](http://www.w3.org/TR/selectors/#specificity)来判断哪些属性值与一个元素最为相关,从而在该元素上应用这些属性值。特异性是基于不同种类选择器组成的匹配规则。 + +简单地说,如果两个 CSS 选择器应用于同一个元素,则使用具有更高特定性的一个。这就是为什么在我们前面的示例中,应用 ID 选择器的属性值,因为它具有更高的特异性值。 + +那么,如何计算选择器的特异性呢? + +## 特异性层次结构 + +计算选择器的特异性值是相当棘手的。计算它的一种方法是使用权重系统对不同的选择器进行排序,以创建层次结构。我们将为每个选择器分配权重,以便更好地了解每个选择器的排名。让我们从最少的开始。 + +### 元素和伪元素 + +我们使用元素选择器(如 `a`、`p` 和 `div`)来设置所选元素的样式,而伪元素(如 `::after` 和 `::before`)用于设置元素特定部分的样式。 + +```css +/* 元素选择器 */ +p { + color: red; +} + +/* 伪元素选择器 */ +p::before { + color: red; +} +``` + +元素和伪元素选择器的特异性最低。在特异性权重系统中,它的值为 1。 + +### 类、属性和伪类 + +以下是类、属性和伪类示例 + +```css +/* 类选择器 */ +.person { + color: plum; +} + +/* 属性选择器 */ +[type='radio'] { + color: plum; +} + +/* 伪类选择器 */ +:focus { + color: plum; +} +``` + +它比元素和伪元素选择器具有更高的特异性。在特异性权重系统中,它的值为 10。 + +### ID 选择器 + +ID 选择器用于使用元素的 ID 来定位元素。 + +```css +/* ID 选择器 */ +#header { + color: plum; +} +``` + +ID 选择器比类和元素具有更高的特异性。在特异性权重系统中,它的值为 100。 + +### 内联样式 + +内联样式直接应用于 HTML 文档中的元素。这是一个例子: + +```html +

I'm Superman

+``` + +内联样式具有最高的特异性。在特异性权重系统中,它的值为 1000。 + +**总结** + +```text +内联样式 - 1000 +ID 选择器 - 100 +类、属性和伪类 - 10 +元素和伪元素 - 1 +``` + +权重较高的选择器的属性值将始终应用于权重较低的选择器。内联样式具有最高的权重,其属性值将覆盖应用于元素的其他选择器的值。例如,如果我们有一个元素,对于相同的属性 `color`,就有一个内联样式。如果类和 ID 选择器也具有相同属性的值,则内联样式将获胜。 + +```html +

I'm Superman

+``` + +```css +#paragraph { + color: pink; +} + +.color-plum { + color: plum; +} +``` + +效果如下: + +![purple](https://upload-images.jianshu.io/upload_images/18281896-a2e73cb245fe730c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +当 ID 选择器和类选择器具有相同属性的值时,也会发生同样的情况。将应用 ID 选择器的属性值。 + +**注意**,仅当不同的选择器具有**相同属性**的值时,权重才适用。 + +### 多个元素选择器 + +有时,多个选择器用于定位元素。例如,下面的列表: + +```html +
    +
  • Item 1
  • +
  • Item 2
  • +
  • Item 3
  • +
+``` + +您可以针对这样的列表项目: + +```css +.list > li { + color: pink; +} +``` + +或 + +```css +ul > li { + color: plum; +} +``` + +如果两个选择器都在同一个样式表上使用,将对列表项应用哪种样式? + +让我们回到我们的权重系统来计算两个选择器的特异性。 + +对于`.list > li`,一个类选择器的权重是 10,一个元素选择器的权重是 1。它们的总和是 11。 + +对于 `ul > li`,一个元素选择器的权重为 1。使用两个元素选择器,因此它们的和为 2。 + +你认为哪些颜色值会被应用? + +如果您说将应用 `.list > li` 选择器的颜色,那就对了。它比其他选择器具有更高的特异性值。 + +效果如下: + +![pink](https://upload-images.jianshu.io/upload_images/18281896-dddbbed3898002c8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +让我们再试一个例子。鉴于此元素: + +```html +
+
+

Item 1

+
+
+``` + +CSS 如下: + +```css +#box-1 > .second-block > .text { + color: pink; +} + +.first-block > #box-2 > #paragraph { + color: plum; +} +``` + +试着计算特异性并猜测哪个 `color` 值适用。 + +效果如下: + +![plum](https://upload-images.jianshu.io/upload_images/18281896-dd59d0ba5fba24b6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +让我们使用我们的权重系统来理解为什么应用第二个选择器的颜色值。 + +对于 `#box-1 > .second block > .text`,我们有一个 ID 选择器和两个类选择器。它们的权重之和是 `100 + 10 + 10 = 120`。 + +对于 `.first block > #div-2> #paragraph`,我们有一个类选择器和两个 ID 选择器。它们的权重之和是 `10 + 100 + 100 = 210`。 + +这就是为什么使用后一个选择器的值。 + +我们再来看一个例子,以确保你已经掌握。 + +```html +
+
    +
  • + First + item +
  • +
+
+``` + +如果样式表中有以下样式,那么将对 `span` 应用哪种颜色? + +```css +div#box > .first-list > #list-item > span { + color: pink; +} + +#list > #list-item > #span { + color: purple; +} + +#box > #list > .first-list-item > .first-span { + color: plum; +} +``` + +尝试计算特异性,并将其与运行代码时得到的结果进行比较。 + +## 关于 CSS 特异性的重要点 + +- 分配给选择器的权重只是让我们知道将哪些规则应用到元素上。然而,这并不总是足够的。例如,您可以假设,如果使用 10 个以上的类(权重 >= 100)作为一个元素的目标,那么属性值将覆盖一个 ID 选择器的属性值。但事实并非如此。只要包含 10 个以上类的选择器且没有 ID 选择器,那么一个 ID 选择器将始终优先于它。 +- `!important` — 任何选择器的属性值都使其成为将应用于元素的值。无论选择器在特异性层次结构上的排名如何,都会发生这种情况。让我们用一个例子来理解这一点。 + +```html +

Item 1

+``` + +如果应用以下样式 + +```css +p { + color: pink !important; +} + +.plum { + color: plum; +} + +#paragraph { + color: purple; +} +``` + +元素选择器 `p` 的值将被使用,因为 `!important` 附加在价值上。然而,如果另一个选择器具有 `!important` 标记附加到相同的属性,则使用后面选择器的值。 + +![important](https://upload-images.jianshu.io/upload_images/18281896-d8581d40472552ce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +这就是为什么应该避免使用 `!important`,因为这样很难覆盖样式。 + +通常,要设置特定元素的样式,最好使用类。这使得在需要时更容易覆盖样式。 + +## 总结 + +1. 由于 CSS 的级联特性,如果对同一个元素应用两个规则,则最后一个规则就是将要使用的规则。 +2. CSS 特异性是一组规则,用于确定哪个样式适用于元素。 + +3. 权重系统是计算不同选择器特异性的一种方法。 + +**以下是权重总结** + +- 内联样式,如 `style="xxx"`,权值为 1000; +- ID 选择器,如 `#content`,权值为 100; +- 类、伪类和属性选择器,如 `.content`、`:hover`、`[attribute]`,权值为 10; +- 元素选择器和伪元素选择器,如`div`、`p`,权值为 1。 + +在同一组属性设置中,`!important` 优先级最高。无论选择器在何处,使用的特异性如何,将覆盖所有其他样式(包括行内样式)。 + +- 相同权重,定义最近者为准:行内样式 > 内部样式 > 外部样式 > 导入样式。 +- 含外部载入样式时,后载入样式覆盖其前面的载入的样式和内部样式。 +- 选择器优先级:`!important > id > class > tag`。 + +- **需要注意的是:通用选择器(`*`)、子选择器(`>`)和相邻同胞选择器(`+`)并不在权重系统中,所以他们的权值都为 0**。 权重值大的选择器其优先级也高,相同权重的优先级又遵循后定义覆盖前面定义的情况。 diff --git "a/CSS/CSS \351\200\211\346\213\251\345\231\250.md" "b/CSS/CSS \351\200\211\346\213\251\345\231\250.md" new file mode 100644 index 0000000..75edac9 --- /dev/null +++ "b/CSS/CSS \351\200\211\346\213\251\345\231\250.md" @@ -0,0 +1,272 @@ +# CSS 选择器 + +> [CSS 选择器](https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Selectors)是 CSS 规则集的一部分,它实际上选择要设置样式的内容。 + +## CSS 选择符 + +**通用选择器**:`*` 将匹配文档的所有元素。不推荐使用通配选择器,因为它是性能最低的一个 CSS 选择器。 + +```css +/* 常用的是清除所有元素的 margin 和 padding */ +* { + margin: 0; + padding: 0; +} + +/* 也可以与子选择器一起使用。 */ +.container * { + border: 1px solid black; +} +``` + +**元素选择器**:选择具有给定节点名称的所有元素。 + +```css +/* input 将匹配任何 元素 */ +input { } +``` + +**ID 选择器**:根据其 `id` 属性值选择一个元素。文档中应只有一个具有给定 ID 的元素。 + +```css +/* 将匹配 ID 为 app 的元素 */ +#app { } +``` + +**类选择器**:选择具有给定 `class` 属性的所有匹配的元素。 + +```css +/* 将匹配具有 .active 类的任何元素 */ +.active { } +``` + +**后代选择器**:` `(空格)选择器选择前一个元素的后代。 + +```css +/* 将匹配 div 元素内部的所有 span 元素(深层嵌套也将被匹配到) */ +div span { } +``` + +**子代选择器**:`>` 选择器选择前一个元素的直接子代的节点。 + +```css +/* 匹配直接嵌套在 ul 元素内的所有 li 元素(深层嵌套将匹配不到) */ +ul > li { } +``` + +**选择器列表**:`,` 是将不同的选择器组合在一起的方法,它选择所有能被列表中的任意一个选择器选中的节点。 + +```css +/* 会同时匹配
元素和 元素 */ +div, span { } +``` + +**通用兄弟选择器**:`~` 选择器选择兄弟元素,位置无须紧邻,只须同层级。 + +```css +/* 匹配同一父元素下,p 元素后的所有 span 元素 */ +p ~ span { } +``` + +**相邻兄弟选择器**:`+` 选择器选择相邻元素,当第二个元素*紧跟在*第一个元素之后,并且两个元素都是属于同一个父元素的子元素,则第二个元素将被选中。 + +```css +/* 会匹配所有相邻在 h2 元素后的 p 元素 */ +h2 + p { } +``` + +**属性选择器**:按照给定的属性,选择所有匹配的元素。 + +```css +/* 选择所有具有 autoplay 属性的元素(不论这个属性的值是什么) */ +[autoplay] { } +``` + +**伪类**:`:` 伪选择器是添加到选择器的关键字,指定要选择的元素的特殊状态。 + +```css +/* 匹配所有曾被访问过的 元素 */ +a:visited { } +``` + +**伪元素**:`::` 伪元素选择器用于表示无法使用 HTML 语义表达的实体。 + +```css +/* 匹配所有

元素的第一行 */ +p::first-line { } +``` + +## 组合选择器 + +> 组合选择器是将两个选择器连接在一起的选择器中的字符。组合选择器有四种类型。 + +- **后代选择器(空格)** +- **子代选择器(>)** +- **通用兄弟选择器(~)** +- **相邻兄弟选择器(+)** + +用法上一节已经讲到。 + +## 属性选择器 + +CSS 属性选择器通过已经存在的属性名或属性值匹配元素。 + +```css +/* 匹配 title 属性的 元素 */ +a[title] { + color: pink; +} + +/* 匹配 href 属性并且属性值为 http:.... 的 元素 */ +a[href='https://github.com/lio-zero/blog'] { + color: plum; +} + +/* 匹配 lang 属性并且属性值为 zh-*(连字符)的 div 元素,例如:zh-CN 或 zh-TW */ +div[lang|='zh'] { + color: plum; +} + +/* 将所有语言为美国英语的

元素的文本颜色设为蓝色 */ +div[lang~="en-us"] { + color: blue; +} + +/* 匹配 href 属性并且属性值包含 www 的 元素 */ +a[href*='www'] { + color: pink; +} + +/* 匹配 href 属性并且属性值开头是 https 的 元素 */ +a[href^='https'] { + color: pink; +} + +/* 匹配 src 属性并且属性值结尾是 .jpg 的 元素 */ +img[src$='.jpg'] { + color: pink; +} +``` + +匹配方式类似正则。 + +属性选择器有多种匹配方式,这节进行扩展介绍。 + +## 伪选择器 + +### 伪类 + +```css +p:lang(language) 为

元素的 lang 属性选择一个开始值 + +input:focus 选择元素输入后具有焦点 +a:link 选择所有未访问链接 +a:visited 选择所有访问过的链接 +a:active 选择正在活动链接 +a:hover 把鼠标放在链接上的状态 +input:valid 选择所有有效值的属性 +#line:target 选择当前活动 #line 元素(点击 URL 包含锚的名字) +input:required 选择有 required 属性指定的元素属性 +input:read-write 选择没有只读属性的元素属性 +input:read-only 选择只读属性的元素属性 +input:out-of-range 选择指定范围以外的值的元素属性 +input:optional 选择没有 required 的元素属性 + +/* CSS3 新增选择器 */ +input[type="text"] 属性选择器 +:root 选择文档的根元素,等同于 html 元素 +:empty 选择没有子元素的元素 +:target 选取当前活动的目标元素 +:not(selector) 选择除 selector 元素意外的元素 + +/* 表单 */ +input:enabled 选择可用的表单元素 +input:disabled 选择禁用的表单元素 +input:checked 选择被选中的表单控件元素(单选框或复选框) + +p:nth-child(n) 匹配父元素下指定子元素,在所有子元素中排序第 n。还有 add、oven +p:nth-last-child(n) 选择所有 p 元素倒数的第二个子元素 +p:nth-of-type(n) 选择所有 p 元素第二个为 p 的子元素 +p:nth-last-of-type(n) 选择所有 p 元素倒数的第二个为 p 的子元素 + +p:first-child 选择器匹配属于任意元素的第一个子元素的 p 元素 +p:last-child 选择所有 p 元素的最后一个子元素 +p:only-child 选择所有仅有一个子元素的 p 元素 +p:only-of-type 选择属于其父元素唯一的 p 元素的每个 p 元素 +p:first-of-type 选择的每个 p 元素是其父元素的第一个 p 元素 +p:last-of-type 选择属于其父元素的最后 p 元素的每个 p 元素 +``` + +### 伪元素 + +```css +p::selection 选择用户选择的元素部分。 +p::before 在每个 p 元素之前插入内容 +p::after 在每个 p 元素之后插入内容 +p::first-line 选择每个 p 元素的第一行 +p::first-letter 选择每个 p 元素的第一个字母 +``` + +## 常见的问题 + +### 伪类和伪元素之间有什么区别? + +伪元素和伪类之所以这么容易混淆,是因为他们的效果类似而且写法相仿。 + +CSS3 为了区分两者,明确规定伪类用一个冒号(`:`)来表示,而伪元素则用两个冒号(`::`)来表示。 + +但因为兼容性的问题,所以现在大部分还是统一的单冒号,但是抛开兼容性的问题,我们在书写时应该尽可能养成好习惯,区分两者。 + +表现形式上作区分:伪类表现的是某种状态被选择,例如 `:hover`、`:checked`,而伪元素表现的是选择元素的某个部分,使这部分看起来像一个独立的元素,例如 `::before` 、`::after`。抽象的说,伪类就是选择元素某种状态,伪元素就是创建一个 HTML 元素。 + +还需要注意: + +- IE 6-7 不支持 `:focus` +- 伪类名称对大小写不敏感 +- 伪元素也有人称为伪对象 + +关于伪类/伪元素的示例可以查阅我最近新开的另一个仓库 [css-tricks](https://github.com/lio-zero/css-tricks),里面提供了大量的 CSS 技巧(包括伪类/伪元素),也可以阅读 [An Ultimate Guide To CSS Pseudo Classes And Pseudo Elements](https://www.smashingmagazine.com/2016/05/an-ultimate-guide-to-css-pseudo-classes-and-pseudo-elements/) 文章。 + +### CSS `content` 属性有什么作用? + +`content` 属性专门应用在 `before/after` 伪元素上,用于插入额外内容或样式。 + +```css +/*

...
*/ +a::before { + content: attr(data-icon); +} +``` + +### CSS 选择器的优先级(特异性)是什么? + +> MDN:浏览器通过**优先级**来判断哪些属性值与一个元素最为相关,从而在该元素上应用这些属性值。优先级是基于不同种类选择器组成的匹配规则。 + +### CSS 权重和优先级 + +权重分为四级,分别是: + +- 内联样式,如 `style="xxx"`,权值为 1000 +- ID 选择器,如 `#content`,权值为 100 +- 类、伪类和属性选择器,如 `.content`、`:hover` 和 `[attribute]`,权值为 10 +- 元素选择器和伪元素选择器,如 `div`、`p`,权值为 1 + +相同权重,以定义最近者为准:行内样式 > 内部样式 > 外部样式 > 导入样式 + +- 含外部载入样式时,后载入样式将覆盖其之前载入的样式和内部样式(只覆盖相同的 CSS 选择器) +- 选择器优先级:`!important > id > class > tag` +- 在同一组属性设置中,`!important` 优先级最高,高于行内样式 + +> **注意:通用选择器(`*`)、子选择器(`>`)和相邻兄弟选择器(`+`)并不在这四个等级中,所以他们的权值都为 0**。权重值大的选择器其优先级也高,相同权重的优先级又遵循后定义覆盖前面定义的情况。 +> +> 详细内容请查看:[优先级](https://developer.mozilla.org/zh-CN/docs/Web/CSS/Specificity) 和 [CSS3 选择器优先级](http://www.w3.org/TR/selectors/#specificity) + +### 浏览器如何解析 CSS 选择器? + +浏览器**从右往左**解析 CSS 选择器,这样的匹配节点的方式能快速、准确的与 render 树上的节点进行匹配,避免了许多无效匹配。浏览器需要评估的规则越少,样式引擎执行的速度就越快。 + +> 详细内容可查看:[Why do browsers match CSS selectors from right to left?](https://stackoverflow.com/questions/5797014/why-do-browsers-match-css-selectors-from-right-to-left) + +### 浏览器如何解析 CSS? + +浏览器如何解析 CSS? diff --git "a/CSS/CSS \351\207\215\347\275\256\345\205\203\347\264\240\346\240\267\345\274\217.md" "b/CSS/CSS \351\207\215\347\275\256\345\205\203\347\264\240\346\240\267\345\274\217.md" new file mode 100644 index 0000000..b53878c --- /dev/null +++ "b/CSS/CSS \351\207\215\347\275\256\345\205\203\347\264\240\346\240\267\345\274\217.md" @@ -0,0 +1,62 @@ +# CSS 重置元素样式 + +## CSS 重置 + +CSS 重置有助于在不同浏览器之间强制实现样式一致性,并为样式元素提供了一个干净的列表。您可以使用诸如 [Normalize](http://necolas.github.io/normalize.css/) 等 CSS 重置库,也可以使用更简化的重置方法: + +```css +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} +``` + +现在,元素将被去除 `margin` 和 `padding`,`box-sizing` 允许您使用 CSS 盒模型管理布局。 + +**注意**:如果遵循下面的[继承 `box-sizing`](https://github.com/AllThingsSmitty/css-protips#inherit-box-sizing) 提示,您可能会选择在 CSS 重置中不包含 `box-sizing` 属性。 + +## 继承 `box-sizing` + +从 `html` 元素继承 `box-sizing`: + +```css +html { + box-sizing: border-box; +} + +*, +*::before, +*::after { + box-sizing: inherit; +} +``` + +这使得在插件或其它组件中更改 `box-sizing` 变得更容易。 + +## 使用 unset 而不是重置所有属性 + +重置元素的属性时,不需要重置每个单独的属性: + +```css +button { + background: none; + border: none; + color: inherit; + font: inherit; + outline: none; + padding: 0; +} +``` + +你可以用 `all` 简写來指定所有元素的属性。 将该值设置为 `unset` 会将元素的属性更改为其初始值: + +```css +button { + all: unset; +} +``` + +> **注意**: IE11 不支持 `all` 和 `unset` 的简写。 diff --git "a/CSS/Flex \345\270\203\345\261\200.md" "b/CSS/Flex \345\270\203\345\261\200.md" new file mode 100644 index 0000000..996ad92 --- /dev/null +++ "b/CSS/Flex \345\270\203\345\261\200.md" @@ -0,0 +1,619 @@ +# Flex 布局 + +Flex 是 Flexible Box 和分配容器中项目之间的空间,即使这些项目的大小未知或是动态。 + +Flex 布局背后的主要思想是让容器能够改变其项目的宽度/高度(和顺序),以最好地方式填充可用空间(主要是为了适应各种显示设备和屏幕大小)。flex 容器扩展项目以填充可用空间,或收缩项目以防止溢出。 + +最重要的是,Flex 布局与常规布局(基于垂直的块和基于水平的内联)相比是方向无关的。虽然这些方法对页面很有效,但它们缺乏灵活性来支持大型或复杂的应用程序(尤其是在方向改变、调整大小、拉伸、收缩等方面)。 + +Flex 布局在 2009 年由 W3C 提出的。它在所有的浏览器都支持: + +![Flex 支持情况](https://upload-images.jianshu.io/upload_images/18281896-edeae6574fa01df3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +> **注意**:Flexbox 布局最适合应用程序的组件和小规模布局,而 Grid 布局则适用于大规模布局。 + +以下内容参考 [Flexbox30](https://www.samanthaming.com/flexbox30/),图片截自 [A Complete Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) + +## 基础概念 + +为了使 Flexbox 正常工作,你需要设置父子关系。父级是 Flex 容器,其中的所有内容都是子级或 Flex 项。 + +**Flex 容器**仅环绕其直接子容器。因此,没有孙子或孙辈的关系。只有父母 <-> 直系子女!只要存在父子关系,就可以建立 Flexbox。因此,孩子也可以成为其孩子的伸缩容器。但这将是一个单独的 flex 容器。而且它不会继承祖父母的 flex 属性。 + +还有一点,关于为什么不能将文本容器设置为 flexbox 容器,可以阅读 [Never make your text container a flexbox container](https://dev.to/afif/never-make-your-text-container-a-flexbox-container-m9p)。 + +![flexbox 属性应用示意图](https://upload-images.jianshu.io/upload_images/18281896-d907e938cdf1d8b7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +Flexbox 在 2 轴系统中运行:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴是你将伸缩项目如何放置在伸缩容器中的定义方向。确定横轴非常简单,它是在垂直于主轴的方向上进行的。 + +记住不要把他比作数学上的 **x** 和 **y** 轴。因为 **x** 轴并不总是主轴。这可能会让你出错。 + +在每个轴上都有一个起点和终点。如果在主轴上,则将起始位置称为 **main start**,将结束位置称为 **main end**。相同的概念适用于交叉轴。知道起点和终点很重要,因为你可以控制 flex 项目的放置位置。 + +项目默认沿主轴排列。单个项目占据的主轴空间叫做 `main size`,占据的交叉轴空间叫做 `cross size`。 + +## 属性 + +父容器和子项目都有自己的一套属性。 + +父容器: + +- `flex-direction` +- `flex-wrap` +- `flex-flow` +- `justify-content` +- `align-items` +- `align-content` + +子项目: + +- `flex-grow` +- `flex-shrink` +- `flex-basis` +- `flex` +- `order` +- `align-self` + +下面,我们会对它们一一讲解。 + +## 父容器 + +![父容器](https://upload-images.jianshu.io/upload_images/18281896-17095dabca7fddc9.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +flex 容器有 2 种类型:`flex` 将创建一个块级 flex 容器,`inline-flex` 将创建一个 inline 级 flex 容器。 + +```css +.parent { + display: flex /* default */ | inline-flex; +} +``` + +很简单地解释,块元素占据了容器的整个宽度。它们看起来像构建块,其中每个构建块彼此堆叠。内联元素仅占用其所需的空间。因此,它们似乎排成一行,或者彼此并排。 + +### flex-direction + +`flex-direction` 定义主轴的属性。记住主轴可以是水平或垂直的。因此,如果我们希望主轴是水平的,则称为行。如果我们希望它是垂直的,那就叫做列。另外,请记住我们有一个主要的起点和终点。我们只需添加一个反向后缀即可将 **main start** 设置为反向。 + +```css +.parent { + flex-direction: row /* default */ | row-reverse | column | column-reverse; +} +``` + +![flex-direction](https://upload-images.jianshu.io/upload_images/18281896-dc080b31fbfebcbb.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +### flex-wrap + +默认情况下,弹性项目将尝试使其自身收缩以适合一行,换句话说,不进行换行。但是,如果你希望 flex 项保持其大小并在容器中的多行中溢出,则可以使用 `flex-wrap: warp;`。此属性将使容器中的弹性项目占用多行。 + +```css +.parent { + flex-wrap: nowrap /* default */ | wrap | wrap-reverse; +} +``` + +![flex-wrap](https://upload-images.jianshu.io/upload_images/18281896-78de20fd7401631e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +`flex-wrap` 允许 flex 项在单独的行上进行包装。但有了 `align-content` 属性,我们可以控制哪些项目行在横轴上的对齐方式。由于这仅适用于包装的项目,所以如果只有一行 flex 项,则此属性不会有任何效果。 + +### flex-flow + +`flex-flow` 是 `flex-direction` 和 `flex-wrap` 的简写。默认值为 row nowrap。如果仅设置一个值,则未设置的属性将采用默认值。 + +```css +.parent { + flex-flow: row nowrap /* default */ | | + | ; +} +``` + +### justify-content + +`justify-content` 设置沿主轴对齐的属性。 + +```css +.parent { + justify-content: flex-start /* default */ | flex-end | center | space-around | + space-between | space-evenly; +} +``` + +![justify-content](https://upload-images.jianshu.io/upload_images/18281896-93eed65c0780566c.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +主轴也可以垂直放置。在这种情况下,将 `flex-direction` 设置为 `column`。 + +```css +.parent { + flex-direction: column; + justify-content: flex-start /* default */ | flex-end | center | space-around | + space-between | space-evenly; +} +``` + +### align-items + +`align-items` 设置沿横轴对齐的属性。记住横轴始终垂直于主轴。 + +```css +.parent { + align-items: stretch /* default */ | flex-start | flex-end | center | baseline; +} +``` + +![align-items](https://upload-images.jianshu.io/upload_images/18281896-5576f5eecc138a73.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +现在,让我们看一下如果交叉轴水平放置,则弹性项目如何对齐。换句话说,伸缩方向是列。 + +```css +.parent { + flex-direction: column; + align-items: stretch /* default */ | flex-start | flex-end | center | baseline; +} +``` + +### align-content + +`align-content` 属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。 + +```css +.parent { + align-content: stretch /* default */ | flex-start | flex-end | center | + space-between | space-around; +} +``` + +![align-content](https://upload-images.jianshu.io/upload_images/18281896-e69c1724d4bd3616.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +### space-evenly 和 space-around + +在 `space-evenly` 中,弹性项目之间的空白空间始终相等。 + +![space-evenly](https://upload-images.jianshu.io/upload_images/18281896-6a1282084a079582.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +但是,在 `space-around` 中,只有内部项目之间的间距相等。第一项和最后一项将仅分配一半的间距。使其具有更加分散的视觉外观: + +![space-around](https://upload-images.jianshu.io/upload_images/18281896-710888f334b0e3e3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +## 子项目 + +![子项目](https://upload-images.jianshu.io/upload_images/18281896-032d8f99bc950f09.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +### order + +默认情况下,弹性项目的显示顺序与在代码中显示的顺序相同。但是,如果你要更改该怎么办?没问题!使用 `order` 属性更改项目的顺序。 + +```css +.child { + order: 0 /* default */ | ; +} +``` + +![order](https://upload-images.jianshu.io/upload_images/18281896-4c9ebe0ac0136af5.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +### flex-grow + +Flexbox 非常适合响应式设计。`flex-grow` 属性允许我们的 flex 项在必要时增长。因此,如果我的容器中有多余的可用空间,我可以告诉某个特定项目按一定比例将其填满。 + +```css +.child { + flex-grow: 0 /* default */ | ; +} +``` + +![flex-grow](https://upload-images.jianshu.io/upload_images/18281896-283032d1033b5b7f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +### flex-shrink + +如果有伸缩空间,`flex-grow` 将会扩展以填充额外的空间。相反 `flex-shrink` 当空间不足时将会控制 flex 项目缩小到适合的程度。请注意,数字越大,缩小幅度越大。 + +```css +.child { + flex-shrink: 1 /* default */ | ; +} +``` + +你可以在 [flex-grow-calculation](https://www.samanthaming.com/flexbox30/22-flex-grow-calculation/) 和 [flex-shrink-calculation](https://www.samanthaming.com/flexbox30/24-flex-shrink-calculation/) 查看浏览器如何帮我们自动处理 `flex-grow` 和 `flex-shrink`,它们是如何计算的出各自该占据多少空间(两者计算方式不同),以及对应的公式。 + +如果你看完了,觉得自己理解了,可以尝试做一下以下两道题: + +- [求最终 left、right 的宽度(变形)](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/382) +- [求最终 left、right 的宽度](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/381) + +### flex-basis + +使用 `flex-basis` 属性可以设置项目的初始大小。你可以将此属性视为 flex 项目的宽度。 + +因此,你的下一个问题可能是 `width` 和 `flex-basis` 之间的区别是什么。当然,你仍然可以使用 `width`,它将仍然有效。 + +它起作用的原因是,如果未设置 `flex-basis`,它将默认为 `width`。因此,你的浏览器将始终尝试查找 `flex-basis` 值作为大小指示符。如果找不到它,那么它别无选择,只能使用 `width` 属性。不要让浏览器做额外的工作。使用适当的 flex 方法并使用 `flex-basis`。 + +```css +.child { + flex-basis: auto /* default */ | ; +} +``` + +当一个项目具有 `flex-basis` 和 `width` 时,浏览器将始终使用 `flex-basis` 设置的值。但要注意,如果同时设置了 `min-width` 和 `max-width`。在这些情况下,`flex-basis` 将丢失,并且不会用作宽度。 + +### flex + +`flex` 属性是上面所提到的 `flex-grow`、`flex-shrink` 和 `flex-basis` 的简写形式。如果你足够了解它们的特性,请使用简写吧! + +```css +.child { + flex: 1 0 auto /* default */ | | + | | | + ; + + /* 相当于: */ + flex-grow: 1; + flex-shrink: 0; + flex-basis: auto; +} +``` + +面试经常会问到的一道 CSS 题是[**弹性盒子中 `flex: 0 1 auto` 表示什么意思**](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/380)?从上面一路看下来,你应该也知道了它们各自表示什么意思。 + +### align-self + +`align-items` 属性可以沿着横轴设置 flex 项。`align-items` 的问题是它强制所有 flex 项使用规则。 + +但是如果你想让他们中的一个打破规则,你可以使用 `align-self`。此属性接受为 `align-items` 提供的所有相同值,因此你可以轻松脱离包装 😎 + +```css +.child-1 { + align-self: stretch /* default */ | flex-start | flex-end | center | baseline; +} +``` + +![align-self](https://upload-images.jianshu.io/upload_images/18281896-cce21923c0d44473.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +## flex 示例 + +### 垂直水平居中元素 + +方式一: + +```css +.container { + display: flex; + justify-content: center; /* horizontal */ + align-items: center; /* vertical */ +} +``` + +方式二: + +```css +.container { + display: flex; +} + +.container > div { + margin: auto; +} +``` + +![水平垂直居中](https://upload-images.jianshu.io/upload_images/18281896-12c537f47dfc6abf.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +对齐 Flexbox 子元素的另一种方法是使用自动外边距。尽管这不是 Flexbox 属性,但要意识到这一点仍然很重要,因为它与 Flexbox 有非常有趣的关系。[Bonus: Aligning with Auto Margins](https://www.samanthaming.com/flexbox30/31-flexbox-with-auto-margins/) + +### 重新排序 + +```css +.container > .top { + order: 1; +} + +.container > .bottom { + order: 2; +} +``` + +### 截断文本 + +```scss +.parent { + display: flex; + align-items: center; + padding: 10px; + margin: 30px 0; +} + +.child { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.child > h2 { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.truncated { + flex: 1; + h2 { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} +``` + +[查看效果](https://codepen.io/lio-zero/pen/OJWXYzG) + +### 移动布局 + +创建固定高度的顶栏和动态高度的内容区域。 + +```css +.container { + display: flex; + flex-direction: column; +} + +.container > .top { + flex: 0 0 60px; +} + +.container > .content { + flex: 1 0 auto; +} +``` + +### 流式布局 + +自动用适当数量的盒子填充可用空间。 + +```css +.container { + display: flex; + flex-wrap: wrap; + align-content: flex-start; + gap: 1rem; +} + +.container > * { + flex: 1 1 10ch; +} +``` + +![流式布局](https://upload-images.jianshu.io/upload_images/18281896-4b2aadd6f1437555.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +[查看效果](https://codepen.io/lio-zero/pen/NWdKNyJ) + +### 响应导航栏 + +```css +.nav { + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + + list-style: none; + margin: 0; + background: deepskyblue; +} + +.nav a { + text-decoration: none; + display: block; + padding: 1em; + color: white; +} + +.nav a:hover { + background: #1565c0; +} + +@media all and (max-width: 800px) { + .nav { + justify-content: space-around; + } +} + +@media all and (max-width: 600px) { + .nav { + flex-flow: column wrap; + padding: 0; + } + .nav a { + text-align: center; + padding: 10px; + border-top: 1px solid rgba(255, 255, 255, 0.3); + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + } + .nav li:last-of-type a { + border-bottom: none; + } +} +``` + +[演示地址](https://codepen.io/lio-zero/pen/xxWMNVX) + +### 固定脚部 + +HTML 结构: + +```html +
+
+
+
+
+``` + +方式一: + +```css +section { + display: flex; + flex-direction: column; +} + +main { + flex-grow: 1; + /* flex: 1 0 auto; */ +} + +footer { + flex-shrink: 0; +} +``` + +方式二: + +```css +section { + display: flex; + flex-direction: column; +} + +footer { + margin-top: auto; +} +``` + +> 推荐:[固定页脚](https://github.com/lio-zero/blog/blob/main/CSS%20Layout/%E5%9B%BA%E5%AE%9A%E9%A1%B5%E8%84%9A.md) + +### 砌体布局 + +```scss +.masonry-container { + display: flex; + flex-direction: column; + flex-wrap: wrap; + max-height: 600px; + .masonry-brick { + margin: 0 0.825rem 0.825rem 0; + + border-radius: 1rem; + } +} + +/* or */ + +.masonry-container { + display: flex; + flex-wrap: wrap; + .masonry-brick { + flex: 1 0 auto; + height: 150px; + margin: 0 0.825rem 0.825rem 0; + border-radius: 1rem; + } +} +``` + +![砌体布局](https://upload-images.jianshu.io/upload_images/18281896-81f3607683a8348f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +[查看效果](https://codepen.io/lio-zero/pen/PobMdVE) + +### 圣杯布局 + +HTML 结构: + +```html +
+
Lorem
+
+ +
Lorem
+ +
+
Lorem
+
+``` + +CSS 样式: + +```css +.container { + display: flex; + flex-direction: column; +} + +main { + display: flex; + flex-direction: row; + flex-grow: 1; +} + +aside { + width: 25%; +} + +article { + flex-grow: 1; +} + +nav { + width: 20%; +} +``` + +[演示地址](https://codepen.io/lio-zero/pen/JjLxqKM) + +你也可以使用 `order` 去调整排列顺序。 + +### 双飞翼布局 + +双飞翼布局其实是根据圣杯布局演化出来的一种布局。 + +```css +.container { + display: flex; + flex-flow: row nowrap; + justify-content: space-around; + height: 100%; +} + +.left, +.right { + width: 200px; + flex-shrink: 1; +} + +.main { + flex-grow: 1; +} +``` + +![双飞翼布局](https://upload-images.jianshu.io/upload_images/18281896-8859b7e288a661e5.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +[查看效果](https://codepen.io/lio-zero/pen/xxgKORY) + +### 两列布局 + +```css +.container { + display: flex; +} + +.left { + width: 200px; + height: 100%; +} + +.right { + flex: 1; + height: 100%; +} +``` + +![两列布局](https://upload-images.jianshu.io/upload_images/18281896-3d629d61426aec35.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +[查看效果](https://codepen.io/lio-zero/pen/yLVmWRY) + +## 更多资料 + +- [Basic concepts of flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) +- [flex 备忘单](https://www.sketchingwithcss.com/samplechapter/cheatsheet.html) +- [Flex 布局教程:语法篇](https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html) +- [Flex 布局教程:实例篇](https://www.ruanyifeng.com/blog/2015/07/flex-examples.html) +- [What Happens When You Create A Flexbox Flex Container?](https://www.smashingmagazine.com/2018/08/flexbox-display-flex-container/) +- [Everything You Need To Know About Alignment In Flexbox](https://www.smashingmagazine.com/2018/08/flexbox-alignment/) +- [Flexbox: How Big Is That Flexible Box?](https://www.smashingmagazine.com/2018/09/flexbox-sizing-flexible-box/) +- [Use Cases For Flexbox](https://www.smashingmagazine.com/2018/10/flexbox-use-cases/) diff --git "a/CSS/Normalize \345\222\214 Reset \347\232\204\345\214\272\345\210\253.md" "b/CSS/Normalize \345\222\214 Reset \347\232\204\345\214\272\345\210\253.md" new file mode 100644 index 0000000..fa8210a --- /dev/null +++ "b/CSS/Normalize \345\222\214 Reset \347\232\204\345\214\272\345\210\253.md" @@ -0,0 +1,67 @@ +# Normalize 和 Reset 的区别 + +每个浏览器都提供一组默认样式,这些样式应用于它呈现的每个网页。默认样式表也称为用户代理样式表。 + +您可以查看以下浏览器各自所提供的默认样式: + +- [Chrome](https://chromium.googlesource.com/chromium/blink/+/master/Source/core/css/html.css) +- [Firefox](https://hg.mozilla.org/mozilla-central/file/tip/layout/style/res/html.css) +- [Safari](https://trac.webkit.org/browser/trunk/Source/WebCore/css/html.css) + +由于默认样式不相同,因此每个浏览器上的网页将具有不同的外观。Normalize 和 Reset CSS 都旨在解决这个问题。 + +顾名思义,Reset CSS 将重置所有内置样式。 + +最流行的 CSS 重置库是 [Meyer's reset](https://meyerweb.com/eric/tools/css/reset/reset.css)。你可以在这里看到完整的代码。例如,它会将 `body` 的 `margin` 重置为 0: + +```css +body { + margin: 0; +} +``` + +如果你使用 Chrome 浏览器的开发者工具,检查任何网页的 `body` 元素,你会发现默认情况下它有 8px 的边距,这是我们通常根本不想要的: + +```css +body { + margin: 8px; +} +``` + +Normalize CSS 是 Reset CSS 的另一种选择。 + +最受欢迎的库是 [normalize.css](https://necolas.github.io/normalize.css/)。它试图使内置的浏览器样式在不同浏览器之间保持一致。 + +除此之外,normalize.css 还使某些元素看起来像我们期望的。例如,Chrome、Firefox 和 Safari 浏览器对 `sub` 和 `sup` 标签使用以下样式: + +```css +sub { + vertical-align: sub; + font-size: smaller; +} + +sup { + vertical-align: super; + font-size: smaller; +} +``` + +它修复跨浏览器的显示错误。你可以查看它的[源代码](https://github.com/necolas/normalize.css/blob/master/normalize.css)看到有很多针对不同浏览器的错误修复,比如 IE、Edge、Firefox 等。 + +如果你使用流行的 CSS 库,你可能不需要在项目中包含 normalize.css。它已经包含在: + +- [Bootstrap's reboot](https://github.com/twbs/bootstrap/blob/master/scss/_reboot.scss#L3) +- [Tachyons](https://github.com/tachyons-css/tachyons/blob/master/src/_normalize.css) +- [TailwindCSS](https://unpkg.com/tailwindcss@1.1.4/dist/base.css) +- etc + +## 更多资料 + +- [sanitize.css](https://github.com/csstools/sanitize.css) 是一个 CSS 库,它提供一致的、跨浏览器的 HTML 元素默认样式以及有用的默认样式 +- [My Custom CSS Reset](https://www.joshwcomeau.com/css/custom-css-reset/) — Josh Comeau 的 CSS 重置 +- [A Modern CSS Reset](https://piccalil.li/blog/a-modern-css-reset/) — Andy Bell 的 CSS 重置 +- [cssremedy](https://github.com/jensimmons/cssremedy/) — Jen Simmons 的 CSS Remedy +- [Open Props](https://open-props.style/) — Adam Argyle 的 Open Props,包含一个自定义 normalize.css +- [minireset](https://github.com/jgthms/minireset.css) 是另一个小型的现代 CSS 重置 +- [Browser Default Styles](https://browserdefaultstyles.com/) 允许我们获取特定元素的各种渲染引擎的默认样式 +- [CSS Reset 与 Sprites](https://github.com/lio-zero/blog/blob/master/CSS/CSS%20Reset%20%E4%B8%8E%20Sprites.md) diff --git a/CSS/PostCSS.md b/CSS/PostCSS.md new file mode 100644 index 0000000..7e8e611 --- /dev/null +++ b/CSS/PostCSS.md @@ -0,0 +1,96 @@ +# PostCSS + +> [PostCSS](https://postcss.org/)(后预处理器)是一种使用 JS 插件转换样式的工具。这些插件可以 lint 你的 CSS,支持变量和 `mixins`,转换未来的 CSS 语法,内联图像等。 + +## 与其他 CSS 预处理器有何不同? + +PostCSS 相比 Sass 或 Less 等 CSS 预处理器提供的主要好处是能够选择自己的路径,并选择所需的功能,同时添加新功能。Sass 或 Less 是固定的,您可以获得许多您可能使用或不使用的功能,但您无法扩展它们。 + +您完全可以使用 PostCSS 代替 Sass 或 Less,但如果你不喜欢,您仍然可以使用 Sass 或 Less,并使用 PostCSS 执行 Sass 无法执行的其他操作,如自动刷新或 linting。 + +你可以编写自己的 [PostCSS 插件](https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md)来做任何你想做的事情。 + +## 安装 PostCSS + +全局安装 [postcss-cli](https://github.com/postcss/postcss-cli): + +```bash +pnpm i -g postcss-cli +``` + +输入以下命令确保其正常工作: + +```bash +postcss --help +``` + +## 常用的插件 + +### Autoprefixer + +[Autoprefixer](https://github.com/postcss/autoprefixer) 解析 CSS 并确定某些规则是否需要供应商前缀。 + +它根据 [Can I Use](http://caniuse.com/) 数据执行此操作,因此您不必担心某个功能是否需要前缀,或者您使用的前缀是否因为过时而不再需要。 + +你可以写出更简洁的 CSS。 + +例子: + +```css +a { + display: flex; +} +``` + +被编译为: + +```css +a { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} +``` + +### PostCSS Preset Env + +[PostCSS Preset Env](https://github.com/csstools/postcss-preset-env) 是 CSS 中的 Babel,允许您将现代 CSS 转换为大多数浏览器都能理解的内容,根据您的目标浏览器或运行时环境确定您需要的 polyfill: + +- 它使用 Autoprefixer 添加前缀(因此,如果使用它,则无需直接使用 Autoprefixer) +- 它允许您使用 CSS 变量 +- 它允许您使用嵌套,就像在 Sass 中一样 +- etc + +### CSS Modules + +[PostCSS Modules](https://github.com/css-modules/postcss-modules) 允许您使用 CSS 模块。 + +CSS 模块不是 CSS 标准的一部分,但它们是具有作用域选择器的构建步骤。 + +### csslint + +Linting 可以帮助您编写正确的 CSS,避免错误或陷阱。[Stylelint](http://stylelint.io/) 插件允许您在构建时删除 CSS。 + +### cssnano + +[cssnano](https://cssnano.co/) 缩小了 CSS 并对代码进行了优化,以在生产中交付最少量的代码。 + +### 其他有用的插件 + +[PostCSS Plugins](https://github.com/postcss/postcss/blob/main/docs/plugins.md#postcss-plugins) 提供了可用插件的完整列表。 + +其中一些: + +- [LostGrid](https://github.com/peterramsing/lost) 是一个 PostCSS 网格系统 +- [postcss-nested](https://github.com/postcss/postcss-nested) 提供了使用 Sass 嵌套规则的能力 +- [postcss-nested-ancestors](https://github.com/toomuchdesign/postcss-nested-ancestors) 引用嵌套 CSS 中的任何祖先选择器 +- [postcss-simple-vars](https://github.com/postcss/postcss-simple-vars) 使用类似 Sass 的变量 +- [PreCSS](https://github.com/jonathantneal/precss) 为您提供了 Sass 的许多功能,这是最接近于完整的 Sass 替代品的功能 + +## 进一步阅读 + +- [An Introduction to PostCSS](https://www.sitepoint.com/an-introduction-to-postcss/) +- [How to Use PostCSS as a Configurable Alternative to Sass](https://www.sitepoint.com/postcss-sass-configurable-alternative/) +- [PostCSS — A Comprehensive Introduction](https://www.smashingmagazine.com/2015/12/introduction-to-postcss/) +- [From Sass to PostCSS](https://tylergaw.com/blog/sass-to-postcss/) diff --git "a/CSS/SASS \351\242\204\345\244\204\347\220\206\345\231\250.md" "b/CSS/SASS \351\242\204\345\244\204\347\220\206\345\231\250.md" new file mode 100644 index 0000000..510bab4 --- /dev/null +++ "b/CSS/SASS \351\242\204\345\244\204\347\220\206\345\231\250.md" @@ -0,0 +1,470 @@ +# SASS 预处理器 + +## 什么是 CSS 预处理器? + +> CSS 预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为 CSS 增加了一些编程的特性,将 CSS 作为目标生成文件,然后开发者就只要使用这种语言进行编码工作。 + +- 通过工具编译成 CSS:开发后,这些特定文件被编译成任何浏览器都可以理解的常规 CSS。 +- 能提升 CSS 文件的组织方式:预处理程序有助于在 CSS 中编写可重用,易于维护和可扩展的代码。 +- 基于 CSS 的另一种语言:CSS 预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为 CSS 增加了一些编程的特性,将 CSS 作为目标生成文件,然后开发者就只要使用这种语言进行编码工作 +- 扩展 CSS:CSS 预处理器为 CSS 增加一些编程的特性,无需考虑浏览器的兼容性问题,例如你可以在 CSS 中使用变量、简单的逻辑程序、函数、插值、mixin 等等在编程语言中的一些基本特性,可以让你的 CSS 更加简洁、适应性更强、可读性更佳,更易于代码的维护等。 + +目前主流的预处理器里有:[SASS(SCSS)](https://sass-lang.com/)、[Less](http://lesscss.org/)、[Stylus](https://stylus.bootcss.com/)、[PostCSS(后预处理器)](https://postcss.org/) + +下面我们将来介绍 `SASS` 预处理器。详细内容查阅 [SASS 文档](https://sass-lang.com/documentation) 。 + +## 什么是 SASS? + +> SASS 是最早的 CSS 预处理语言,有比 Less 更为强大的功能。但因其一开始的缩进式语法并不能被开发者们接受,所以使用率不高,不过由于其强大的功能和 Ruby on Rails 的大力推动,逐渐被更多开发者使用。 + +> SASS 是采用的 Ruby 语言编写的一款 CSS 预处理语言,它诞生于 2007 年,是最早成熟 CSS 预处理脚本语言,它被解释或编译成级联样式表。它允许您编写可维护的 CSS,并提供变量、嵌套、混合、扩展、函数、循环、条件等功能。最初它是为了配合 HAML 而设计的,因此有着和 HAML 一样的缩进式风格。 + +## SASS 和 SCSS 有什么区别? + +> `SASS` 从第三代开始,放弃了缩进式风格,并且完全向下兼容普通的 `CSS` 代码,这一代的 `SASS` 也被称为 `SCSS`。`SCSS` 完全继承了 `SASS` 中的功能,并引入了一些新语法特性。 + +主要有两点不同: + +- 文件扩展:SASS 的后缀扩展名为 `.sass`,而 SCSS 的 后缀为扩展名为 `.scss` +- 语法书写:SASS 是以严格的缩进式语法规则来书写,不带大括号 `{}` 和分号 `;`,而 SCSS 书写方式更像 CSS。 + +## 变量 + +`SASS` 变量很简单:您可以为以 `$` 开头的名称分配一个值,然后可以引用该名称而不是值本身。 + +```scss +$red: #833; + +body { + color: $red; +} +``` + +变量可以减少重复,进行复杂的数学运算,配置库等。 + +### CSS 变量与 SASS 变量的区别 + +- `SASS` 变量都是由 `SASS` 编译出来的。CSS 变量包含在 CSS 中输出。 +- CSS 变量对于不同的元素可以有不同的值,但是 `SASS` 变量一次只有一个值。 +- `SASS` 变量是必需的,这意味着如果您使用一个变量然后更改它的值,那么前面的使用将保持不变。CSS 变量是声明性的,这意味着如果您更改该值,它将影响前面使用和后面使用的。 + +## 嵌套 + +`SASS` 允许开发人员以嵌套的方式使用 CSS。 + +```scss +.markdown-body { + a { + color: blue; + &:hover { + color: red; + } + } +} +``` + +### 引用父级选择器 `&` + +`SASS` 允许在嵌套的代码块内,使用 `&` 引用父元素 + +```scss +a { + font-size: 14px; + font-weight: bold; + text-decoration: none; + &:hover { + text-decoration: underline; + font-size: 20px; + } +} +``` + +### 嵌套属性 + +CSS 许多属性都位于相同的命名空间,例如 `text-align`、`text-decoration`、`text-transform` 都位于 font 命名空间下,`SASS` 当中只需要编写命名空间一次,后续嵌套的子属性都将会位于该命名空间之下。 + +```scss +text: { + align: center; // 将编译为 text-align: center + decoration: underline; // 将编译为 text-decoration: underline + transform: uppercase; // 将编译为 text-transform: uppercase +} +``` + +注意,`text` 后面必须加上冒号。 + +## 注释 + +```scss +// 单行注释,该注释方式只保留在 SASS 源文件中,编译后被省略。此注释不会包含在 CSS 中。 + +/* 多行注释,该注释方式会保留到编译后的文件。但压缩模式下,仍会被删除 */ +/* 多行注释可以使用插值表达式 #{1 + 1} */ + +/*! 即使在压缩模式下也会包含此注释。*/ +``` + +## 继承 + +`@extend` 指令用于继承另一个选择器的样式。相同样式直接继承,不会造成代码冗余; + +```scss +.button { + font-size: 14px; + color: plum; +} + +.push-button { + @extend .button; +} +``` + +## 混合 + +混合(`Mixin`)允许您定义可以在整个样式表中重用的样式。 + +**语法** + +```scss +@mixin { ... } + +// 带参数 +@mixin name() { ... } +``` + +**示例** + +```scss +@mixin heading-font { + font-family: sans-serif; + font-weight: bold; +} + +h1 { + @include heading-font; +} +``` + +`Mixin` 特性在添加浏览器兼容性前缀的时候非常有用。 + +```scss +@mixin border-radius($radius) { + border-radius: $radius; + -ms-border-radius: $radius; + -moz-border-radius: $radius; + -webkit-border-radius: $radius; +} + +.card { + @include border-radius(8px); +} +``` + +### 参数 + +你可以向 `Mixin` 传递变量参数来让代码更加灵活。 + +```scss +@mixin font-size($n) { + font-size: $n * 1.2em; +} + +body { + @include font-size(2); +} +``` + +### 具有默认值 + +```scss +@mixin pad($n: 10px) { + padding: $n; +} + +body { + @include pad(15px); +} +``` + +### 具有默认变量 + +```scss +// 设置默认值 +$default-padding: 10px; +@mixin pad($n: $default-padding) { + padding: $n; +} + +body { + @include pad(15px); +} +``` + +## 引入 SCSS 模块 + +`SASS` 能够将代码分割为多个片段,并以下划线作为其命名前缀。`SASS` 会通过这些下划线来辨别哪些文件是 `SASS` 片段,并且不让片段内容直接生成为 CSS 文件,只在使用 `@import` 指令的位置被导入。 + +```scss +// _variables.scss +$gray-1: #eee; + +// index.scss +@import './_variables'; +``` + +`.scss` 或 `.sass` 扩展名是可选的。 + +## 函数 + +### 颜色功能 + +**颜色设置** + +SASS 提供了一些内置的颜色函数,以便生成系列颜色。 + +```scss +// RGBA +rgb(100, 120, 140) +rgba(100, 120, 140, .5) +rgba($color, .5) + +// 修改 HSLA +complement($color) // 像 adjust-hue(_, 180deg) +invert($color) +grayscale($color) +hsla(hue, saturation, lightness, alpha) +``` + +**颜色操作** + +```scss +// 混合 +mix($a, $b, 10%) // 10% a, 90% b + +// 修改 HSLA +darken($color, 5%) +lighten($color, 5%) +saturate($color, 5%) +desaturate($color, 5%) +adjust-hue($color, 15deg) +fade-in($color, .5) // 又名 opacify() +fade-out($color, .5) // aka transparentize() - 将不透明度减半 +rgba($color, .5) // 将 alpha 设置为 .5 + +// 调整 +// 按固定数量变动 +adjust-color($color, $blue: 5) +adjust-color($color, $lightness: -30%) // 像 darken(_, 30%) +adjust-color($color, $alpha: -0.4) // 像 fade-out(_, .4) +adjust-color($color, $hue: 30deg) // 像 adjust-hue(_, 15deg) + +// 通过百分比更改 +scale-color($color, $lightness: 50%) + +// 完全更改一个属性 +change-color($color, $hue: 180deg) +change-color($color, $blue: 250) +``` + +支持:`$red`、`$green`、`$blue`、`$hue`、`$saturation`、`$lightness`、`$alpha` + +**颜色获取** + +```scss +// HSLA +hue($color) // 0deg-360deg 返回颜色在 HSL 色值中的角度值 (0deg - 255deg)。 +saturation($color) // 0%-100% +lightness($color) // 0%-100% +alpha($color) // 0-1 (类似 opacity()) + +// RGB +red($color) // 从一个颜色中获取其中红色值(0-255) +green($color) +blue($color) +``` + +### 其他功能 + +**字符串** + +```scss +unquote('hello') +quote(hello) +to-upper-case(hello) +to-lower-case(hello) +str-length(hello world) +str-slice(hello, 2, 5) // "ello" - it's 1-based, not 0-based +str-insert("abcd", "X", 1) // "Xabcd" +``` + +**单位** + +```scss +unit(3em) // 'em' +unitless(100px) // false +``` + +**数字** + +```scss +floor(3.5) +ceil(3.5) +round(3.5) +abs(3.5) +min(1, 2, 3) +max(1, 2, 3) +percentage(.5) // 50% +random(3) // 0..3 +``` + +**选择器** + +```scss +selector-append('.menu', 'li', 'a') // .menu li a +selector-nest('.menu', '&:hover li') // .menu:hover li +selector-extend(...) +selector-parse(...) +selector-replace(...) +selector-unify(...) +``` + +**其他** + +```scss +variable-exists(red) // 判断变量是否在当前的作用域下。 +mixin-exists(red-text) // 检测指定混入 (mixinname) 是否存在。 +function-exists(redify) // 检测指定的函数是否存在 +global-variable-exists(red) // 检测某个全局变量是否定义。 +``` + +## 循环语句 + +SASS 提供了以下循环: + +**for 循环** + +```scss +@for $i from 1 through 4 { + .item-#{$i} { + left: 20px * $i; + } +} +``` + +**each 循环(简单)** + +```scss +$menu-items: home about services contact; + +@each $item in $menu-items { + .photo-#{$item} { + background: url('images/#{$item}.jpg'); + } +} +``` + +**each 循环(嵌套)** + +```scss +$backgrounds: (home, 'home.jpg'), (about, 'about.jpg'); + +@each $id, $image in $backgrounds { + .photo-#{$id} { + background: url($image); + } +} +``` + +**while 循环** + +```scss +$i: 6; +@while $i > 0 { + .item-#{$i} { + width: 2em * $i; + } + $i: $i - 2; +} +``` + +## 条件语句 + +```scss +@if $position == 'left' { + position: absolute; + left: 0; +} @else if $position == 'right' { + position: absolute; + right: 0; +} @else { + position: static; +} +``` + +## 插值语句 + +通过 `#{}` 插值语句(interpolation)以在选择器或属性名中使用变量: + +```scss +$name: card; +$attr: border; + +.#{$class} { + #{$attr}-color: plum; +} + +@media #{$tablet} + +font: #{$size}/#{$line-height} +url("#{$background}.jpg"); +``` + +## 列表 + +> SASS 列表(List)函数用于处理列表,可以访问列表中的值,向列表添加元素,合并列表等。 +> +> SASS 列表是不可变的,因此在处理列表时,返回的是一个新的列表,而不是在原有的列表上进行修改。 +> +> 列表的起始索引值为 1,记住不是 0。 + +```scss +$list: (a b c); + +nth($list, 1) // 从 1 开始 +length($list) // 返回列表的长度 + +// 其他属性 +nth // 函数可以直接访问数组中的某一项 +join // 函数可以将多个数组连接在一起 +list-separator(list) // 返回一列表的分隔符类型。可以是空格或逗号。 +append(list, value, [separator]) // 将单个值 value 添加到列表尾部。separator 是分隔符,默认会自动侦测,或者指定为逗号或空格 +is-bracketed(list) // 判断列表中是否有中括号 +index(list, value) // 返回元素 value 在列表中的索引位置。 +zip($list) // 将多个列表按照以相同索引值为一组,重新组成一个新的多维度列表。 +set-nth(list, n, value) // 设置列表第 n 项的值为 value。 + +// 遍历列表中的每一项 +@each $item in $list { ... } +``` + +## Map + +> SASS Map(映射)对象是以一对或多对的 `key/value` 来表示。 +> +> SASS Map 是不可变的,因此在处理 Map 对象时,返回的是一个新的 Map 对象,而不是在原有的 Map 对象上进行修改。 + +```scss +$map: (key1: value1, key2: value2, key3: value3); + +map-get($map, key1) // 返回 Map 中 key 所对应的 value(值)。如没有对应的 key,则返回 null 值。 +map-has-key($map, key1) // 判断 map 是否有对应的 key,存在返回 true,否则返回 false。 +map-keys($map) // 返回 map 中所有的 key 组成的队列。 +map-merge($map1, $map2) // 合并两个 map 形成一个新的 map 类型,即将 map2 添加到 map1的尾部 +map-remove($map, keys...) // 移除 map 中的 keys,多个 key 使用逗号隔开。 +map-values($map) // 返回 map 中所有的 value 并生成一个队列。 +``` + +## 更多资料 + +- [CSS Preprocessors Explained](https://www.freecodecamp.org/news/css-preprocessors/#:~:text=CSS%20Preprocessors%20compile%20the%20code,preprocessor%20were%20not%20in%20place.) +- [What is a CSS Preprocessors & Why Use Them](https://sherocommerce.com/what-is-a-css-preprocessors-why-use-them/) diff --git "a/CSS/calc() \345\267\245\344\275\234\345\216\237\347\220\206.md" "b/CSS/calc() \345\267\245\344\275\234\345\216\237\347\220\206.md" new file mode 100644 index 0000000..bc20895 --- /dev/null +++ "b/CSS/calc() \345\267\245\344\275\234\345\216\237\347\220\206.md" @@ -0,0 +1,221 @@ +# calc() 工作原理 + +CSS3 `calc()` 函数允许我们在声明 CSS 属性值时执行以下计算,也就数学运算(`+`、`-`、`*`、`/`)。 + +例如,我们不必声明元素宽度的静态像素值,我们可以使用 `calc()` 来指定宽度是两个或多个数值相加的结果。 + +```css +.foo { + width: calc(100px + 20px); +} +``` + +## `calc()` + +如果您使用过像 SASS 这样的 CSS 预处理器,你肯定遇到过上面的这种写法。 + +```scss +.nav { + width: 100px + 20px; +} + +// SASS 中可以直接相加 +.foo { + width: 100px + 20px; +} + +// 或者使用变量 +$first-width: 100px; +$second-width: 20px; + +.bar { + width: $first-width + $second-width; +} +``` + +但是,`calc()` 函数提供了一个更好的解决方案,原因有两个。 + +- **我们可以合并不同的单位**。具体来说,我们可以将相对单位(如百分比(`%`)和视口单位(`vw`、`vh`、`vmax`、`vmin`))与绝对单位(如像素(`px`))混合。例如,我们可以创建一个表达式,用百分比值减去像素值。 + +> 单位详细介绍可查看:[CSS 单位及其需要注意的地方](https://github.com/lio-zero/blog/blob/master/CSS/CSS%20%E5%8D%95%E4%BD%8D%E5%8F%8A%E5%85%B6%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E5%9C%B0%E6%96%B9.md)。 + +```css +.sidebar { + width: calc(100% - 120px); +} +``` + +在本例中,`.sidebar` 元素的宽度总是比其父元素宽度的 `100%` 小 `120px`。 + +- 对于 `calc()`,**计算的值是表达式本身**,而不是表达式的结果值。使用 CSS 预处理器处理数学表达式时,给浏览器的值就是表达式的结果值。 + +```scss +// SCSS 中指定的值 +.foo { + width: 100px + 20px; +} + +// 在浏览器中编译 CSS 和计算值 +.foo { + width: 120px; +} +``` + +但是,浏览器解析的值是实际表达式。 + +```scss +// CSS 中指定的值 +.foo { + width: calc(100% - 120px); +} + +// 浏览器中的计算值 +.foo { + width: calc(100% - 120px); +} +``` + +这意味着浏览器中的值可以更动态,并随着视口的变化而调整。我们可以有一个高度为视口减去绝对值的元素,它将随着视口的变化而调整。 + +## 使用 `calc()` + +`calc()` 函数可用于对数值执行**加减乘除**计算。也就是可以与 ``、``、``、`
  • ` 标签,你会得到其中的每个 `emoji`。 + +> 你可以在这 👉[测试效果](https://codepen.io/lio-zero/pen/YzZLLqq),配合下文进行阅读。 + +能得到这样的结果是因为,它使用了事件冒泡一个最重要的原理:**事件委托(event delegation)**,后面我们会介绍到。 + +## IE 中的事件流 + +这里要介绍一下 IE 6-8 中的事件流,IE 6-8 中的事件流和标准的 DOM 事件流有(独)所(领)不(风)同(骚),IE 的事件流只支持事件冒泡,不支持事件捕获。 + +IE 9 之前,它不支持 `addEventListener`,也就不能使用其第三个参数来表示是冒泡还是捕获,它提供了非标准的事件监听器 `attachEvent()` 方法。 + +在这个模型中,事件对象使用 `event.srcElement` 属性,而不是 `event.target`,但两者的效果相同。 + +```js +emoji.attachEvent('onclick', function (e) { + var target = e.target || e.srcElement + console.log(target.innerHTML) +}) +``` + +## 什么是事件冒泡? + +**事件冒泡(默认模式)**是事件传播的一种,其中事件首先在目标元素上触发,然后在同一嵌套层次结构中依次在目标元素的祖先(父代)上触发,直到到达最外层的 DOM 元素。 + +```js +emoji.onclick = () => { + alert(11) +} + +smile.onclick = () => { + alert(22) +} +``` + +当你点击 `smile` 元素时,首先弹出 22,然后才是 11。同一层次结构的事件由内到外依次执行。 + +## 什么是事件捕获? + +**事件捕获**也是事件传播的一种,其中事件首先被最外层的元素捕获,然后在同一嵌套层次结构中依次触发目标元素的后代(子元素),直到到达最里面的 DOM 元素。 + +当一个事件发生以后,它会在不同的 DOM 节点之间传播(propagation)。[DOM 事件](http://www.w3.org/TR/DOM-Level-3-Events/)标准描述了事件传播的 3 个阶段: + +- **捕获阶段(capture phase)** — 事件从 `window` 对象向下传递到目标元素。 +- **目标阶段(target phase)** — 事件到达目标元素。 +- **冒泡阶段(bubbling phase)** — 事件从目标元素上开始冒泡。 + +在捕获阶段中,事件从祖先元素向下传播到目标元素。当事件达到目标元素后,冒泡才开始。 + +同时,这三个阶段的传播模型,会使得一个事件在多个节点上触发。 + +因为浏览器默认是从事件冒泡开始,我们看不到事件捕获,所以想要测试事件捕获,我们需要使用到 `addEventListener` 方法,`addEventListener` 用于添加事件句柄、注册监听器,第三个参数还可以指定在捕获阶段还是冒泡阶段触发事件: + +- `false`(默认值)— 在冒泡阶段开始触发事件 +- `true` — 在捕获阶段开始触发事件 + +```js +smile.addEventListener('click', (e) => { + console.log(e.target.innerHTML) +}) + +emoji.addEventListener( + 'click', + (e) => { + alert('Emoji List') + }, + true +) + +document.addEventListener('click', () => { + alert('document') +}) + +window.addEventListener('click', () => { + alert('window') +}) +``` + +运行上面代码,点击 `smile` 元素时,将依次输出 **'Emoji List' -> 😀 -> 'document' -> 'window'**。 + +**原因**:由于 `ul` 被我们设置为捕获阶段,所以它先被触发,然后在触发点击的目标元素事件,然后在依次往上冒泡。 + +> **注意**:捕获阶段不会在某些特殊事件(例如 `focus`)和 IE < 9 时出现。 + +## 事件委托(Event Delegation) + +事件委托,也称为事件代理,是指将本要添加在自身的事件,添加到别人身上。通过冒泡的原理,将事件添加到父级,触发执行效果。 + +例如本文的示例,我们不必为列表的每个子项添加事件,而是添加在其父级上,当我们触发某一项时,通过事件冒泡到父级,从而触发事件。 + +```js +emoji.addEventListener('click', (e) => { + console.log(e.target.innerHTML) +}) +``` + +**好处**: + +- 节省内存占用,减少事件注册 +- 新增子元素时,无需再对其进行事件绑定 + +## 阻止事件传播 + +你可以通过调用事件的 `event.stopPropagation()` 方法来阻止捕获和冒泡阶段中当前事件在 DOM 中的进一步传播。 + +```js +function handler(e) { + // do something... + + // 通常在事件处理程序的末尾 + e.stopPropagation() +} +``` + +## 阻止事件的默认行为 + +浏览器对某些事件操作有一些默认行为。例如: + +- `click` 事件 — 点击元素时会触发该事件,默认行为是跳转到链接指向的页面。 +- `submit` 事件 — 提交表单时会触发该事件,默认行为是提交表单数据到服务器。 +- `keydown` 事件 — 按下键盘按键时会触发该事件,默认行为取决于按下的按键。例如,按下 `Enter` 键会提交表单,按下 `Tab` 键会使焦点跳到下一个输入字段。 +- `dragstart` 事件 — 开始拖动元素时会触发该事件,默认行为是拖动元素。 +- `drop` 事件 — 在拖动元素上释放鼠标时会触发该事件,默认行为是将拖动的数据放入目标元素中。 + +还有很多类型的事件,默认行为可能不同。为了确保页面的正常工作,如果在需要时,你可以使用以下方法来阻止默认行为的发生。 + +### 对于 `on` 返回 `false` + +```js +ele.onclick = function (e) { + // do something + + return false +} +``` + +如果你使用内联属性,则情况相同: + +```html +
    + +
    +``` + +我不推荐这种方法,因为: + +- 返回 `false` 没有意义 +- 它不适用于 `addEventListener()` 方法 + +### 使用 `preventDefault()` 方法 + +此方法适用于内联属性: + +```html + +``` + +和事件处理程序: + +```js +ele.onclick = function (e) { + e.preventDefault() + // ... +} + +ele.addEventListener('click', function (e) { + e.preventDefault() + // ... +}) +``` + +你还可以在事件对象中使用 `event.defaultPrevented` 查看是否使用了 `event.preventDefault()` 方法。 + +它返回一个布尔值用来表明是否在特定元素中调用了 `event.preventDefault()`。 + +```js +function handler(e) { + e.preventDefault() + console.log(e.defaultPrevented) // true +} +``` + +## 很高兴你知道 + +- 事件本身在传播,而不是绑定在事件上的方法会传播。 +- 并非所有的事件都会传播,如 `focus`、`blur`、`mouseenter` 和 `mouseleave` 等事件传播。 +- 你应该知道哪些事件触发会有默认行为(如提交表单、点击链接等),并在需要时阻止它们。 +- 建议使用 `addEventListener` 来注册事件处理程序,不要使用 HTML 元素的属性来注册事件处理程序(如 `onclick`),因为这样可能会有潜在的安全隐患。如果传递给 `onclick` 属性的方法不存在,浏览器也不会发出警告。 +- 事件处理程序的返回值通常会被忽略,唯一的例外是使用 `on` 分配的处理程序中返回 `return false`。在所有其他情况下,`return` 值都会被忽略,且返回 `true` 没有意义。 +- 如果是使用 `on` 分配的处理程序,那么你可以使用 `return false` 来阻止默认行为。 +- 如果是使用 `addEventListener` 分配的处理程序,那么你可以使用 `event` 事件对象中的 `e.preventDefault()` 方法来阻止默认行为的发生。 +- `return false` 做着与 `event.stopPropagation()` 和 `event.preventDefault()` 类似的工作,但它们之间毫无关联。 +- 为了避免内存泄漏问题,请记住将不再使用的事件处理程序移除。 + +```js +const handler = (e) => { + // do something... + + // 不在使用时,请移除它 + ele.removeEventListener('click', handler) +} + +// 附加事件监听器 +ele.addEventListener('click', handler) +``` diff --git "a/DOM/clientY \344\270\216 pageY \347\232\204\345\214\272\345\210\253.md" "b/DOM/clientY \344\270\216 pageY \347\232\204\345\214\272\345\210\253.md" new file mode 100644 index 0000000..b726611 --- /dev/null +++ "b/DOM/clientY \344\270\216 pageY \347\232\204\345\214\272\345\210\253.md" @@ -0,0 +1,31 @@ +# clientY 与 pageY 的区别 + +给定页面中的一个点,`clientY` 和 `pageY` 是从该点到视口和页面顶部的距离(以像素为单位)。 + +在这里,page 是整个渲染的页面,其中可能有滚动条,而 viewport 是页面的可见部分。 + +``` +┌─────────────────────────────┬─┐◀︎─── Web page ▲ +| | | | +| | | | +| | | | +| | | | +| | | | +| | | | +| | | pageY +| | | | +├=============================┼─┤ ▲ | ▲ +| | | | | | +| | | | | | +| Scroll bar ──────────▶︎| | | | clientY +| | | Browser | | +| | | window | | +| ● Point | | | ▼ ▼ +| | | | +| | | | +├=============================┼─┤ ▼ +| | | +| | | +| | | +└─────────────────────────────┴─┘ +``` diff --git "a/DOM/keydown\343\200\201keypress \345\222\214 keyup.md" "b/DOM/keydown\343\200\201keypress \345\222\214 keyup.md" new file mode 100644 index 0000000..47da625 --- /dev/null +++ "b/DOM/keydown\343\200\201keypress \345\222\214 keyup.md" @@ -0,0 +1,31 @@ +# keydown、keypress 和 keyup + +## 事件顺序 + +当用户按下一个键或不同的组合键时,按以下顺序触发 `keydown`、`keypress` 和 `keyup`: + +- 当用户按下按键时,会首先触发 `keydown` 事件 +- 用户释放按键时,最后触发 `keyup` 事件 +- 在这之间,`keypress` 事件将被触发 + +这些事件用于不同的目的。 + +`keydown` 和 `keyup` 事件经常被用来处理物理按键,而 `keypress` 事件被用来处理其正在键入的字符。 + +`keypress` 会忽略某些按键,诸如 `delete`、`arrows`、`page up`、`page down`、`home`、`end`、`ctrl`、`alt`、`shift` 和 `esc` 等。所以,如果我们需要处理这些键,最好使用两种 `keydown` 或 `keyup` 事件。 + +> **Tips**:MDN 解释 `keypress` 事件因高度依赖硬件且已被弃用,建议不要在浏览器中使用它。 + +下面的示例代码监听 `keydown` 事件,并在按下 `ESC` 键时执行一些操作: + +```js +document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + // do something ... + } +}) +``` + +如果用户按住某个键,则 `keydown` 和 `keypress` 事件会触发多次。 + +而 `keyup` 仅在用户释放按键时触发一次。 diff --git "a/DOM/key\343\200\201keyCode \345\222\214 which.md" "b/DOM/key\343\200\201keyCode \345\222\214 which.md" new file mode 100644 index 0000000..515b1ec --- /dev/null +++ "b/DOM/key\343\200\201keyCode \345\222\214 which.md" @@ -0,0 +1,37 @@ +# key、keyCode 和 which + +`key`、`keyCode` 和 `which` 可用于确定按下哪个键。下面是处理文本框的按键事件的示例代码。 + +它检查用户是否按下键码为 13 的 **Enter** 键: + +```js +document.addEventListener('keydown', function (e) { + if (e.keyCode === 13) { + // do something ... + } +}) +``` + +## 区别 + +根据 MDN 文档,[`keyCode`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode) 和 [`which`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/which) 都已弃用,将从 Web 标准中删除。 + +除此之外,浏览器对这两个属性的支持也有所不同。有些浏览器使用 `keyCode`,有些浏览器使用 `which`。 + +通常可以看到一些规范化的写法,如下所示: + +```js +const key = 'which' in e ? e.which : e.keyCode +// or +const key = e.which || e.keyCode || 0 +``` + +## 建议 + +建议使用 [`key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) 属性。上面的示例代码可以重写为: + +```js +if (e.key === 'Enter') { + // 按下回车键 +} +``` diff --git "a/DOM/mouseenter \344\270\216 mouseover \347\232\204\345\214\272\345\210\253.md" "b/DOM/mouseenter \344\270\216 mouseover \347\232\204\345\214\272\345\210\253.md" new file mode 100644 index 0000000..a6bdf81 --- /dev/null +++ "b/DOM/mouseenter \344\270\216 mouseover \347\232\204\345\214\272\345\210\253.md" @@ -0,0 +1,12 @@ +# mouseenter 与 mouseover 的区别 + +将鼠标移到元素或其子元素上时,将触发 `mouseenter` 和 `mouseover` 事件。但是它们之间有一些细微的差别: + +- `mouseenter` 事件仅在鼠标移入元素时触发,而不包括移入元素的子元素。对应的鼠标离开元素事件是 `mouseleave`。 +- `mouseover` 事件在鼠标移入元素或其任何子元素时触发,包括移入元素的子元素。对应的鼠标离开元素事件是 `mouseout`。 + +## 建议 + +因为 `mouseover` 事件是从子元素向上通过层次结构传播的,所以如果你正在对该事件执行资源密集型任务,你可能会注意到屏幕闪烁。 + +**建议改用 `mouseenter` 和 `mouseleave`事件。** diff --git "a/DOM/naturalWidth \344\270\216 width \347\232\204\345\214\272\345\210\253.md" "b/DOM/naturalWidth \344\270\216 width \347\232\204\345\214\272\345\210\253.md" new file mode 100644 index 0000000..8e9b9a5 --- /dev/null +++ "b/DOM/naturalWidth \344\270\216 width \347\232\204\345\214\272\345\210\253.md" @@ -0,0 +1,24 @@ +# naturalWidth 与 width 的区别 + +`naturalWidth` 是元素的自然宽度,它永远不会改变。例如,即使使用 CSS 或 JavaScript 调整图像大小,100px 宽的图像的自然宽度始终为 100px。 + +而 `width` 是 `width` 属性的值。它可能会发生更改,并且可以通过 CSS 或 JavaScript 进行更新。 + +我们可以通过给定 `url` 加载的图像的获取自然宽度: + +```js +const getNaturalWidth = (url) => { + return new Promise((resolve, reject) => { + const img = new Image() + img.addEventListener('load', () => { + resolve(img.naturalWidth) + }) + img.addEventListener('error', () => reject()) + img.src = url + }) +} + +getNaturalWidth('https://path/to/image.png').then((naturalWidth) => { + // ... +}) +``` diff --git "a/DOM/nodeName \344\270\216 tagName \347\232\204\345\214\272\345\210\253.md" "b/DOM/nodeName \344\270\216 tagName \347\232\204\345\214\272\345\210\253.md" new file mode 100644 index 0000000..5cc601f --- /dev/null +++ "b/DOM/nodeName \344\270\216 tagName \347\232\204\345\214\272\345\210\253.md" @@ -0,0 +1,38 @@ +# nodeName 与 tagName 的区别 + +`nodeName` 和 `tagName` 是获取 HTML 节点名称的属性。 + +`tagName` 用于获取节点类型为 1 的元素节点的类型。对于属性、注释、文本等其他类型的节点,使用 `nodeName` 获取节点的名称。 + +让我们看看下面的例子,我们有一个简单的按钮: + +```js + +``` + +HTML 元素的 `nodeName` 和 `tagName` 属性相同: + +```js +const button = document.getElementById('login') +button.nodeType // 1 +button.nodeName // 'BUTTON' +button.tagName // 'BUTTON' +``` + +让我们访问表示 `id` 属性的节点: + +```js +const idNode = button.getAttributeNode('id') +idNode.nodeType // 2 +idNode.nodeName // 'id' +idNode.tagName // undefined +``` + +以类似的方式,按钮文本节点为 `nodeName` 和 `tagName` 提供不同的结果: + +```js +const content = button.firstChild +content.nodeType // 3 +content.nodeName // '#text' +content.tagName // undefined +``` diff --git "a/DOM/parentElement \344\270\216 parentNode \347\232\204\345\214\272\345\210\253.md" "b/DOM/parentElement \344\270\216 parentNode \347\232\204\345\214\272\345\210\253.md" new file mode 100644 index 0000000..d9cff24 --- /dev/null +++ "b/DOM/parentElement \344\270\216 parentNode \347\232\204\345\214\272\345\210\253.md" @@ -0,0 +1,52 @@ +# parentElement 与 parentNode 的区别 + +首先,你需要知道元素和节点之间的区别。总之,元素是一种特殊类型的节点,它表示 DOM 树中的单个节点。它不仅可以是元素,还可以是注释、文档、文本节点等。 + +- `parentElement` 属性返回当前元素的父元素。 +- `parentNode` 属性返回当前元素的父节点,即当前元素的直接父元素。 + +在大多数情况下,`parentElement` 和 `parentNode` 属性返回相同的节点: + +```js +// 两者都返回 元素 +document.body.parentNode +document.body.parentElement +``` + +两者的行为相同。 + +但是,当当前元素的父节点是文档片段(document fragment)时,两者的行为就不同了。`parentNode` 属性会返回文档片段,而 `parentElement` 属性则返回 `null`。 + +```js +// 返回文档节点 +document.documentElement.parentNode // document + +// 返回 null,因为 元素不存在父元素节点 +document.documentElement.parentElement // null +``` + +也就是说,如果父节点不是元素节点,则 `parentElement` 属性为 `null`。 + +所以如果你想获取一个元素的父元素,最好使用 `parentElement`。 + +## 提示 + +通过检查父元素是否存在,我们可以从给定元素移动到 `html` 标签: + +```js +while ((ele = ele.parentElement)) { + // ... +} +``` + +下面的代码计算从给定元素到页面顶部的距离: + +```js +const distanceToTop = (ele) => { + let x = 0 + while ((ele = ele.parentElement)) { + x += ele.offsetTop + } + return x +} +``` diff --git "a/DOM/stopImmediatePropagation \344\270\216 stopPropagation.md" "b/DOM/stopImmediatePropagation \344\270\216 stopPropagation.md" new file mode 100644 index 0000000..fe6ad9a --- /dev/null +++ "b/DOM/stopImmediatePropagation \344\270\216 stopPropagation.md" @@ -0,0 +1,26 @@ +# stopImmediatePropagation 与 stopPropagation + +`stopImmediatePropagation()` 方法可以防止事件像 `stopPropagation()` 方法一样冒泡到父元素。但是,它会阻止调用相同事件的其他监听器。 + +假设我们将处理同一事件的不同侦听器附加到相同元素。当事件发生时,监听器的执行顺序与添加的顺序相同。 + +如果在给定的监听器中调用 `stopImmediatePropagation()` 方法,则不会调用其余的监听器。 + +在下面的示例代码中,有 3 个监听器处理由 `button` 表示的按钮的单击事件。 + +```js +button.addEventListener('click', function () { + console.log('foo') +}) + +button.addEventListener('click', function (e) { + console.log('bar') + e.stopImmediatePropagation() +}) + +button.addEventListener('click', function () { + console.log('baz') +}) +``` + +单击按钮将在控制台中打印 `foo` 和 `bar`。我们不会看到 `baz`,因为最后一个监听器没有被调用。 diff --git "a/DOM/\344\272\213\344\273\266\345\257\271\350\261\241\344\270\212\347\232\204 currentTarget \344\270\216 target \345\261\236\346\200\247.md" "b/DOM/\344\272\213\344\273\266\345\257\271\350\261\241\344\270\212\347\232\204 currentTarget \344\270\216 target \345\261\236\346\200\247.md" new file mode 100644 index 0000000..45d28af --- /dev/null +++ "b/DOM/\344\272\213\344\273\266\345\257\271\350\261\241\344\270\212\347\232\204 currentTarget \344\270\216 target \345\261\236\346\200\247.md" @@ -0,0 +1,73 @@ +# 事件对象上的 currentTarget 与 target 属性 + +`currentTarget` 和 `target` 是监听特定事件时事件对象的属性,例如: + +```js +document.addEventListener('click', (e) => { + console.log(e.currentTarget) + console.log(e.target) +}) +``` + +## 区别 + +`currentTarget` 属性表示事件绑定到的当前元素。在上面的示例代码中,`e.currentTarget` 是 `document`。 + +在 `click` 事件的情况下,`target` 是用户单击的元素。它可以是原始元素或其任何子元素,具体取决于用户单击的位置。 + +## 用例 + +下面是一个用例,演示了这两个属性的用法。 + +假设我们在屏幕中央显示了一个模态框。模态框被放置在覆盖层内,覆盖层采用屏幕的全尺寸。 + +结构非常简单,如下所示: + +```html + +
    + + +
    +``` + +用户在单击覆盖层时关闭模态框是一种常见的体验。 + +有两种方法可以做到这一点,但首先,我们需要获取模态框和覆盖层的元素: + +```js +const overlay = document.getElementById('overlay') +const modal = document.getElementById('modal') +``` + +**第一种方法**:当用户单击覆盖层时,我们关闭模态框: + +```js +overlay.addEventListener('click', () => { + console.log('关闭模态框') +}) +``` + +**如果用户在模态框内单击会发生什么**?我们不希望事件冒泡到父元素(即覆盖层),因此调用 `stopPropagation` 方法: + +```js +modal.addEventListener('click', (e) => { + e.stopPropagation() +}) +``` + +`stopPropagation()` 方法用于阻止捕获和冒泡阶段中当前事件在 DOM 中的进一步传播。示例中,我们阻止模态框的点击事件冒泡到父元素。 + +> **Tips**:了解 [JavaScript 事件传播机制](https://github.com/lio-zero/blog/blob/main/DOM/JavaScript%20%E4%BA%8B%E4%BB%B6%E4%BC%A0%E6%92%AD%E6%9C%BA%E5%88%B6.md)可以帮助你更好的理解上面的做法。 + +**第二种方法**:为了确保用户单击覆盖区域而不是模态内部,我们可以简单地检查 `currentTarget` 和 `target` 属性是否引用相同的元素: + +```js +overlay.addEventListener('click', (e) => { + if (e.currentTarget === e.target) { + console.log('关闭模态框') + } +}) +``` + +第二种方法比第一种方法简单得多,并且不需要处理模态框的 `click` 事件。 diff --git "a/DOM/\344\273\216 DOM \344\270\255\347\247\273\351\231\244\344\270\200\344\270\252\345\205\203\347\264\240.md" "b/DOM/\344\273\216 DOM \344\270\255\347\247\273\351\231\244\344\270\200\344\270\252\345\205\203\347\264\240.md" new file mode 100644 index 0000000..aa91249 --- /dev/null +++ "b/DOM/\344\273\216 DOM \344\270\255\347\247\273\351\231\244\344\270\200\344\270\252\345\205\203\347\264\240.md" @@ -0,0 +1,11 @@ +# 从 DOM 中移除一个元素 + +- 使用 `Element.parentNode` 获得给定元素的父节点。 +- 使用 `Element.removeChild()` 从其父节点中删除给定元素。 + +```js +const removeElement = (el) => el.parentNode.removeChild(el) + +// 从 DOM 中移除 .ele +removeElement(document.querySelector('.ele')) +``` diff --git "a/DOM/\344\273\216 DOM \345\205\203\347\264\240\344\270\255\347\247\273\351\231\244\346\211\200\346\234\211\345\255\220\345\205\203\347\264\240.md" "b/DOM/\344\273\216 DOM \345\205\203\347\264\240\344\270\255\347\247\273\351\231\244\346\211\200\346\234\211\345\255\220\345\205\203\347\264\240.md" new file mode 100644 index 0000000..c912876 --- /dev/null +++ "b/DOM/\344\273\216 DOM \345\205\203\347\264\240\344\270\255\347\247\273\351\231\244\346\211\200\346\234\211\345\255\220\345\205\203\347\264\240.md" @@ -0,0 +1,37 @@ +# 从 DOM 元素中移除所有子元素 + +给定 DOM 中的一个项目列表,使用 `querySelector()` 获取它,如下所示: + +```js +const parent = document.querySelector('.parent-element') +``` + +要删除其所有子元素,你有几个不同的解决方案。 + +最快的解决方案是使用 DOM 元素的 `innerHTML` 或 `textContent` 属性来移除所有子元素: + +```js +parent.innerHTML = '' +``` + +另一个解决方案是,创建一个循环,检查 `firstChild` 属性是否存在,然后使用 DOM 元素的 `removeChild()` 方法将其删除: + +```js +while (parent.firstChild) { + parent.removeChild(parent.firstChild) +} +``` + +当 `parent` 的所有子元素都被移除时,循环结束。 + +还有一种方法是使用 `Node.remove()`,如果你的浏览器支持这个方法,可以直接调用: + +```js +while (parent.firstElementChild) { + parent.firstElementChild.remove() +} +``` + +## 更多资料 + +[从 DOM 中移除一个元素](https://github.com/lio-zero/blog/blob/main/DOM/%E4%BB%8E%20DOM%20%E4%B8%AD%E7%A7%BB%E9%99%A4%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0.md) diff --git "a/DOM/\344\273\216\347\273\231\345\256\232\346\226\207\346\234\254\344\270\255\345\216\273\351\231\244 HTML.md" "b/DOM/\344\273\216\347\273\231\345\256\232\346\226\207\346\234\254\344\270\255\345\216\273\351\231\244 HTML.md" new file mode 100644 index 0000000..6039e5a --- /dev/null +++ "b/DOM/\344\273\216\347\273\231\345\256\232\346\226\207\346\234\254\344\270\255\345\216\273\351\231\244 HTML.md" @@ -0,0 +1,49 @@ +# 从给定文本中去除 HTML + +## 从伪元素获取文本内容(不推荐) + +```js +const stripHTML = (html) => { + // 创建新元素 + const ele = document.createElement('div') + + // 设置它的 HTML + ele.innerHTML = html + + // 只返回文本 + return ele.textContent || '' +} +``` + +不建议使用这种方法,因为如果 `html` 包含特殊的标记,例如 ` +``` + +- 如果您正在使用带有 `target ="_ blank"` 的外部链接,则您的链接应具有 `rel="noopener"` 属性,以防止标签被挪用。如果您需要支持旧版本的 Firefox,请使用 `rel="noopener noreferrer"` +- 总结:`rel="noopener"` 应用于超链接,防止打开的链接操纵源页面 + +## 为什么最好把 link 标签放在 head 之间? + +- 把 `` 标签放在 `` 之间是规范要求的内容。此外,这种做法可以让页面逐步呈现,提高了用户体验。 +- 将样式表放在文档底部附近,会使许多浏览器(包括 Internet Explorer)不能逐步呈现页面。 +- 一些浏览器会阻止渲染,以避免在页面样式发生变化时,重新绘制页面中的元素。 +- 这种做法可以防止呈现给用户空白的页面或没有样式的内容。 + +## 为什么最好把 JS 的 script 标签放在 body 之前,有例外情况吗? + +- 脚本在下载和执行期间会阻止 HTML 解析。把 ` +``` + +- Canvas 的一些预期用途包括构建图形、动画、游戏和图像合成。 +- Canvas 元素用于在网页上绘制图形,该元素标签强大之处在于可以直接在 HTML 上进行图形操作 + +#### Canvas 和 SVG 的区别 + +| Canvas | SVG | +| -------------------------------------------------- | -------------------------------------------------------- | +| 基于栅格(由像素组成) | 基于矢量(由形状组成),非常适合 UI/UX 动画 | +| 依赖分辨率 | 不依赖分辨率 | +| 不支持事件处理器 | 支持事件处理器 | +| 文本渲染能力差 | 良好的文字渲染功能 | +| 使用更多的对象或更小的曲面或两者都提供更好的性能 | 复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快) | +| 最适合图像密集型的游戏,其中的许多对象会被频繁重绘 | 不适合游戏应用 | +| 仅通过脚本修改 | 通过脚本和 CSS 修改 | +| 能够以 .png 或 .jpg 格式保存结果图像 | 多个图形元素,成为页面 DOM 树的一部分 | +| 可伸缩性差。不适合以较高分辨率打印。可能发生像素化 | 更好的可扩展性。可以任何分辨率高质量打印。不会发生像素化 | + +#### 100 \* 100 的 canvas 占多少内存? + +- [100\*100 的 canvas 占多少内存](https://juejin.cn/post/6844903704139661326) + +#### 您如何为您的网站选择 svg 或 canvas? + +- 如果你知道你需要矢量艺术,则选择 SVG。与 JPG 之类的栅格图形相比,矢量艺术在视觉上是清晰的,并且文件大小通常较小。 +- 像一个小的平面颜色图标,这显然是 SVG 的领域。 +- 像互动游戏,那显然是 Canvas。 + +#### 参考 + +- [Canvas API](https://www.bookstack.cn/books/webapi-tutorial) +- [SVG 图像](https://www.bookstack.cn/read/webapi-tutorial/docs-svg.md) + +- [How to Choose Between Canvas and SVG](https://www.sitepoint.com/how-to-choose-between-canvas-and-svg/) +- [何时使用 SVG 与何时使用 canvas](https://css-tricks.com/when-to-use-svg-vs-when-to-use-canvas/) + +### 新标签 + +#### 新语义和结构元素 + +- `canvas` 标签定义图形,比如图表和其他图像。该标签基于 JavaScript 的绘图 API + +```html + 抱歉,您的浏览器不支持canvas元素 +``` + +- `figure` 是当您想要显示带有标题的图像时经常使用的语义标签。经常与 `img` 和 `figcaption` 标签配合使用。 +- `figcaption` 标签包含标题文本。 + +```html + + +
    + D.O +
    An elephant at sunset
    +
    +``` + +- `summary` 利用了一个 `details` 元素的一个内容的摘要,标题或图例。 +- `details` 可创建一个挂件,仅在被切换成展开状态时,它才会显示内含的信息。 + - 标签用于描述文档或文档某个部分的细节。 + - 给他来点动画效果:[如何对 Details 元素进行动画处理](https://css-tricks.com/how-to-animate-the-details-element/) + +```html + + +
    + Details + Something small enough to escape casual notice. +
    +``` + +- `header`、`nav`、`main`、`footer`、`section`、`article` + +```html +
    +
    +
    + +
    +
    +
    +
    +``` + +- `map` 定义一个客户端图像映射。图像映射(image-map)指带有可点击区域的一幅图像 + - area 元素永远嵌套在 map 元素内部。area 元素可定义图像映射中的区域。 + +```html +
    + pic + + + + + + +
    +``` + +- `mark` 突出显示 html 中的文本。在这个标签出现之前,常使用使用 `em` 或 `strong` 赋予突出显示的内容一些语义。现在不推荐了。如果需要突出显示,请使用此标签 + +```html +

    Lio

    +``` + +默认背景颜色 `` 是黄色 + +```css +/* default style */ +mark { + background: yellow; + color: black; +} +``` + +可以使用 CSS 自定义样式 + +```css +mark { + background: red; + color: white; +} +``` + +- `meter` 标签定义已知范围或分数值内的标量测量,也被称为 gauge(尺度)。它不应用于指示进度(在进度条中)。如果标记进度条,请使用 `progress` 标签。 + +```html +
    + 4/10
    + 60% +
    +``` + +- `progress` 标签标示任务的进度(进程)。 + +```html + +32% +``` + +- `time` 定义日期或时间。Edge、Firefox 和 Safari 都支持 `
    ` 标签中的文本通常会保留空格和换行符。而文本也会呈现为等宽字体。
    +- `strong` 用于指示比周围文本更重要的文本,例如警告或错误。从语义上讲,它的重要性。它显示为粗体
    +- `b` 与 `strong` 非常相似,因为它也显示为粗体。然而,与它不同的是,它并没有真正传达出任何重要性,它更像是一种文体而非语义。
    +- `em` 用于强调某个词。它显示为斜体
    +
    +```html
    +lorem
    +lorem
    +lorem
    +```
    +
    +- `q` 和 `blockquote`
    +  - `q` 引号
    +  - `blockquote` 块引号
    +
    +```html
    +lorem
    +
    lorem
    +``` + +- `bdo` 可以更改 HTML 文本的方向。 + - `rtl`:从右到左。`ltr`:从左到右。 + +```html +

    This text will go right to left.

    +``` + +- 使用 `abbr` 标签缩写您的代码,当你传递一个标题时,它将创建一个工具提示 + - `` 不同浏览器的默认样式有些不同。在 Chrome 和 Firefox 中,它将带有下划线,并且在悬停时将带有 `title` 传递的值的工具提示。如果您在 Safari 上打开此页面,则不会出现下划线。此外,仅当您具有 `title` 属性时才显示下划线。 + - 由于跨浏览器的差异,建议为 `` 代码加上自定义样式。这样,您将在浏览器之间拥有一致的外观 + +定义术语时,可以与 `dfn` 混合使用 + +```html + TIL something awesome! +``` + +指示的非缩写词并将其输出到页面上的括号中 + +```css +abbr[title]::after { + content: ' (' attr(title) ')'; +} +``` + +利用 `hover` 状态仅在点击时显示非缩写词 + +```css +abbr[title]:hover::after { + content: ' (' attr(title) ')'; +} +``` + +使用 `abbr` 标签来指示在顺序键盘导航中是可聚焦的 `tabindex="0"`,然后在聚焦时触发我们的非缩写内容。 + +```html +TIL +``` + +```css +abbr[title]:focus::after { + content: ' (' attr(title) ')'; +} +``` + +也可以使用一些提示工具,如 Bootstrap 的[工具提示](https://getbootstrap.com/docs/4.5/components/tooltips/)组件。 + +- `kbd` 和 `code` + - `kbd`:表示用户从键盘、语音输入或任何其他文本输入设备输入的文本。 + - `code`:表示计算机代码的简短片段的文本。 + - 两者使用同样的 `monospace` 字体。但是在语义上它们是不同的。最好使用 `kbd` 代替 `code` + +```html +Ctrl + C Ctrl + C +``` + +```css +/* Default Style */ +kbd { + font-family: monospace; +} + +kbd, +code { + border: 1px solid gray; + border-radius: 5px; + padding: 5px; +} +``` + +- `s` 和 `del` 删除线 + - `s` 当您尝试表示不再相关或不再准确的事物时,使用它。 + - `del` 当您要指示某些内容已从文档中删除时,使用它。 + - 它们都是删除线。但是,它们传达了关于内容的不同含义。 + +```html +Lorem ipsum dolor sit amet. + + +$1999 +$99 + +Lorem ipsum dolor sit amet. + + +
      +
    • 打卡
    • +
    • 喝杯咖啡
    • +
    +``` + +- `ins` + +```html +

    + Lorem ipsum + dolor sit amet consectetur adipisicing elit. Perferendis, rem. +

    +``` + +- [20 HTML Elements for Better Text Semantics](https://www.sitepoint.com/20-html-elements-better-text-semantics/) + +- [有哪些被低估未被广泛使用的有用的 HTML 标签?](https://www.zhihu.com/question/396745068/answer/1262953923) + +### 新属性 + +- `contenteditable` + - `contenteditable` 属性应用于任何 HTML 元素,它可以像 `input` 或 `` 那样工作编辑它们 + - 您可以为其添加事件监听器,监听其内容变化 + - `contenteditable` 属性值有 3 个不同的值:true、false、inherit + +```html +
    +

    元素可编辑

    +
    +
    +

    元素不可编辑

    +
    +
    +

    元素继承其父元素的可编辑状态

    +
    +``` + +- `input` + - `required` 必须输入内容。 + - `autofocus` 属性能够让 `button`,`input` 或 `textarea` 元素在页面加载完成时自动成为页面焦点 + - `pattern` 用正则表达式验证 + +```html + + + + + + + + +``` + +- **HTML5 新的表单输入类型?** + - 新输入类型(type 13 种):`date`、`month`、`week`、`time`、`number`、`range`、`email`、`url`、`color`、`datatime-local`、`datetime`、`search`、`tel` + - `search`:用于搜索域,比如站点搜索或 Google 搜索,域显示为常规的文本域。 + - `url` :用于应该包含 URL 地址的输入域在提交表单时,会自动验证 url 域的值。 + - `email`:用于应该包含 e-mail 地址的输入域,在提交表单时,会自动验证 email 域的值。 + - `datetime`:选取时间、日、月、年(UTC 时间) + - `date`:选取日、月、年 + - `month`:选取月、年 + - `week`:选取周和年 + - `time`:选取时间(小时和分钟) + - `datetime-local`:选取时间、日、月、年(本地时间) + - `number`:用于应该包含数值的输入域,您还能够设定对所接受的数字的限定。 + - `range`:用于应该包含一定范围内数字值的输入域,类型显示为滑动条。 + - `color`:定义拾色器。 + - `tel`:定义用于输入电话号码的字段。 + - 其中 `datetime` 不在被推荐使用,转而使用 `datatime-local` + +```html + + + + + + + + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +- `hiden` 属性规定对元素进行隐藏。 + - 可以对 `hidden` 属性进行设置,使用户在满足某些条件时才能看到某个元素(比如选中复选框,等等)。然后,可使用 JavaScript 来删除 hidden 属性,使该元素变得可见。 + +```html + +``` + +- `Download` + - 锚点标签的默认设置是导航链接,它将转到您在 `href` 属性中指定的链接 + - 添加 `download` 属性时,它将变成一个下载链接。提示您要下载的文件。下载的文件将具有与原始文件名相同的名称。但是,您也可以通过将值传递给 `download` 属性来设置自定义文件名 + - `download` 属性仅适用于同源 URL。如果的 `href` 来源与网站的来源不同,那么它将无法正常工作。换句话说,您只能下载属于该网站的文件。此属性遵循**同源策略**中的相同规则概述。 + +```html +
    使用原始文件名下载本地文件 + + 使用自定义文件名下载 logo.png +``` + +- [同源政策](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) +- [浏览器同源政策及其规避方法](http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html) + +### HTML5 的 form 如何关闭自动完成功能? + +- 将 `input` 设置为 [`autocomplete=off`](https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion) + +```html + + + + +
    + + +
    +``` + +### ` + + +``` + +> **注意**:没有 `src` 属性的脚本(即不是内联脚本),`async` 和 `defer` 属性会被忽略。 + +### 如何处理 HTML5 新标签的浏览器兼容问题?如何区分 HTML 和 HTML5? + +- IE6-8 支持通过 `document.createElement` 方法产生的标签,利用这一特性让这些浏览器支持 HTML5 新标签 +- 使用 [html5shiv](https://github.com/aFarkas/html5shiv) 框架 + +- HTML5: + - DOCTYPE 声明 + - 新增的语义元素(`
    `、`
    ` 等) + - 新增功能元素 + +### HTML5 的构成要素是什么? + +- 语义:提供更准确地描述内容。 +- 连接:提供新的方式与服务器通信。 +- 离线和存储:允许网页在本地存储数据并有效地离线运行。 +- 多媒体:在 Open Web 中,视频和音频被视为一等公民(first-class citizens)。 +- 2D/3D 图形和特效:提供更多种演示选项。 +- 性能和集成:提供更快的访问速度和性能更好的计算机硬件。 +- 设备访问:允许使用各种输入、输出设备。 +- 外观:可以开发丰富的主题。 +- [HTML5](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5) + +### Modernizr + +- [Modernizr](https://github.com/Modernizr/Modernizr) 是一个用来检测浏览器功能支持情况的 JavaScript 库。 +- 通过这个库我们可以检测不同的浏览器对于 HTML5 特性的支持情况。 + +```html +
    +

    通过 Modernizr 检测 HTML5 特性

    +
    + + +``` + +### HTML5 存储 + +#### localStorage + +[`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) 持久化的本地存储,除非是通过 js 删除,或者清除浏览器缓存,否则数据永远不会过期,关闭浏览器也不会丢失。 + +- HTML5 修订 `localStorage` 取代 `globalStorage` +- 在同源的所有标签页和窗口之间共享数据 +- 数据仅保存在客户端,不与服务器进行通信,对数据的操作是同步的 +- 大小限制为 5M;但实际 JavaScript 中的字符串为 UTF-16,因此每个字符需要两个字节的内存。这意味着尽管许多浏览器的限制为 5MB,但您只能存储 2.5M 个字符。 +- 浏览器的支持情况:IE7 及以下版本不支持 web storage。但在 IE5-7 中有个 userData,其实也是用于本地存储。 + +#### sessionStorage + +[`sessionStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage) 存储对象存储一个会话的数据,数据会在浏览器关闭后自动删除。 + +- 跟 `localStorage` 一样,大小限制最多为 5M。 +- 同一个会话的页面才能访问并且当会话结束后数据也会随之销毁,因此 sessionStorage 不是一种持久化的本地存储 +- 与 `localStorage` 拥有统一的 API 接口; +- `localStorage` 有自己独立的存储空间; +- 对数据的操作是同步的。 +- [localStorage 还能这么用](https://iammapping.com/the-other-ways-to-use-localstorage/) +- [给 localStorage 加上过期时间](https://juejin.im/post/6844903825304731656) +- [不同类型浏览器存储的入门](https://css-tricks.com/a-primer-on-the-different-types-of-browser-storage/) +- [前端存储除了 localStorage 还有啥](https://juejin.cn/post/6844904192549584903#heading-12) + +#### cookie、sessionStorage 和 localStorage 的区别 + +- 都是在客户端以键值对存储的存储机制,并且只能将值存储为字符串。 + +| | cookie | localStorage | sessionStorage | +| -------------------------------------------------- | -------------------------------------------------- | ------------ | -------------- | +| 由谁初始化 | 客户端或服务器,服务器可以使用`Set-Cookie`请求头。 | 客户端 | 客户端 | +| 过期时间 | 手动设置 | 永不过期 | 当前页面关闭时 | +| 在当前浏览器会话(browser sessions)中是否保持不变 | 取决于是否设置了过期时间 | 是 | 否 | +| 是否随着每个 HTTP 请求发送给服务器 | 是,Cookies 会通过`Cookie`请求头,自动发送给服务器 | 否 | 否 | +| 容量(每个域名) | 4kb | 5MB | 5MB | +| 访问权限 | 任意窗口 | 任意窗口 | 当前页面窗口 | + +#### 什么是 WebSQL? + +- WebSQL 是使用 SQL 的客户端(浏览器)的数据库 API。 +- Web SQL 数据库 API 并不是 HTML5 规范的一部分,但是它是一个独立的规范,引入了一组使用 SQL 操作客户端数据库的 APIs。 +- 并非所有浏览器都支持[WebSQL](https://caniuse.com/#search=websql)。 +- 现在[不推荐使用](https://www.w3.org/TR/webdatabase/) WebSQL ,而是使用 IndexedDB 代替它。 + +#### 什么是 IndexedDB? + +> IndexedDB 是一种底层异步 API,浏览器内置的数据库,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。 + +- 它将将数据存储为键值对。 +- 大多数浏览器都支持 [IndexedDB](http://caniuse.com/#feat=indexeddb)。 + +> IndexedDB API 功能强大,但对于简单的情况可能看起来太复杂如果你更喜欢一个简单的 API,请尝试 [localForage](https://localforage.github.io/localForage/),[dexie.js](http://www.dexie.org/),[PouchDB](https://pouchdb.com/),[IDB](https://www.npmjs.com/package/idb),[IDB-KEYVAL](https://www.npmjs.com/package/idb-keyval),[JsStore](https://jsstore.net/) 或者 [lovefield](https://github.com/google/lovefield) 之类的库,这些库使 IndexedDB 对开发者来说更加友好。 + +- [IndexedDB](https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API) +- [浏览器数据库 IndexedDB 入门教程](http://www.ruanyifeng.com/blog/2018/07/indexeddb.html) + +#### 为什么在 HTML5 中使用 IndexedDB 代替 WebSQL? + +IndexedDB 像一个 NoSQL 数据库,而 WebSQL 像关系型数据库,使用 SQL 查询数据。W3C WebSQL 已经不再支持这种技术。 + +#### HTML5 应用程序缓存(Application Cache) + +根据最新的标准,该特性已经从 Web 标准中删除,建议使用 [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers) 代替。这里找了一些资料,感兴趣了解一下。 + +- [有趣的 HTML5:离线存储](http://segmentfault.com/a/1190000000732617) +- [Using the application cache](https://developer.mozilla.org/en-us/docs/Web/HTML/Using_the_application_cache) +- [HTML5-离线缓存(Application Cache)](https://mp.weixin.qq.com/s/Q-Z8kYWSUJpkpAkTBv1Igw) + +### 什么是 Web Workers? + +- Web Workers 帮助我们在后台运行 JavaScript 代码,而不会阻止应用程序。 +- Web Workers 在一个隔离的(新的)线程中运行,用于执行 JavaScript 代码,并且通过 postMessage 将结果回传到主线程。这样就不会阻塞主线程的运行。 +- Web Workers 通常用于大型任务。 +- Web Workers 需要一个单独的文件来存储我们的 JavaScript 代码。 +- Web Workers 文件是异步下载的 。 +- 所有最新的浏览器均支持 [Web Worker](https://caniuse.com/webworkers)。 + +客户端 js: + +```js +var myWebWorker = new Worker('task.js') // 创建 worker + +// 监听 task.js worker 消息 +worker.addEventListener( + 'message', + function (event) { + console.log('Worker said: ', event.data) + }, + false +) + +// 启动工作程序 +worker.postMessage('From web worker file') +``` + +task.js(工作文件)文件: + +```js +// 监听客户端 JS 文件发布消息 +self.addEventListener( + 'message', + function (event) { + // 处理后的数据发送到客户端监听 JS 文件 + self.postMessage(event.data) + }, + false +) +``` + +- [使用 Web Worker 加速 JavaScript 应用程序](https://blog.teamtreehouse.com/using-web-workers-to-speed-up-your-javascript-applications) + +### WebSocket + +- WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 +- WebSocket 是一种在客户端与[服务器](https://developer.mozilla.org/zh-CN/docs/Glossary/Server)之间保持[TCP](https://developer.mozilla.org/zh-CN/docs/Glossary/TCP)长连接的[网络协议](https://developer.mozilla.org/zh-CN/docs/Glossary/Protocol),可以随时进行信息交换。 +- WebSocket 使用 ws 或 wss 的统一资源标志符,类似于 HTTPS,其中 wss 表示在 TLS 之上的 Websocket。 +- 默认情况下,Websocket 协议使用 80 端口;运行在 TLS 之上时,默认使用 443 端口。 + +**WebSocket 如何兼容低浏览器?** + +- Adobe Flash Socket +- ActiveX HTMLFile(IE) +- 基于 multipart 编码发送 XHR +- 基于长轮询的 XHR + +**websocket 与 socket 的区别**: + +Socket 是传输控制层协议,WebSocket 是应用层协议。更多请看参考 + +**更多学习资料**: + +- [WebSocket 介绍和 Socket 的区别](https://blog.csdn.net/qushaming/article/details/90747326) +- [WebSocket 教程](http://www.ruanyifeng.com/blog/2017/05/websocket.html) +- [WebSocket](https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket) +- [WebSocket 是什么原理?为什么可以实现持久连接?](https://www.zhihu.com/question/20215561/answer/40316953) + +### Geolocation API 如何在 HTML5 中工作? + +- HTML5 [Geolocation API](https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/geolocation)(地理定位)允许用户在需要时向 web 应用程序提供用户的位置。出于隐私原因,用户需要获得报告位置信息的权限。 +- JavaScript 可以捕获你的纬度和经度,并可以发送到后端 Web 服务器,做一些奇特的位置感知的事情,比如找到本地企业或在地图上显示你的位置 +- 如今,大多数浏览器和移动设备都[支持](https://www.caniuse.com/?search=geolocation) Geolocation API +- Geolocation API 通过 `navigator` 获取对象。 + +```js +if ('geolocation' in navigator) { + /* geolocation 是可用的 */ +} else { + /* geolocation 是不可用的 */ +} +``` + +- 使用 `navigator.geolocation.getCurrentPosition()` 方法获取用户的位置 + +### 页面可见性(Page Visibility)API 可以有哪些用途? + +- 页面可见性 API 提供了您可以观察的事件,刹车了解文档何时可见或隐藏,以及查看页面当前可见性状态的功能。 +- 使用选项卡式浏览,任何给定网页都有可能在后台,因此对用户不可见。页面可见性 API 提供了您可以观察的事件,以便了解文档何时可见或隐藏,以及查看页面当前可见性状态的功能。 +- `document.hidden` 返回一个布尔值。 + - true 表示页面可见,false 则表示页面隐藏。 + - 不同页面之间来回切换,将触发 [visibilitychange](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/visibilitychange_event) 事件。 +- `document.visibilityState`:表示页面所处的状态,当前页面的可见性,有四个取值 + - `visible`:页面彻底不可见。 + - `hidden`:页面至少一部分可见。 + - `prerender`:页面即将或正在渲染,处于不可见状态。 + - `unloaded`:已被废弃,不在使用。 +- 只要 `document.visibilityState` 属性发生变化,就会触发 `visibilitychange` 事件 + +```js +// 打开新的页面,来回切换标签页,观察页面标题的变化 +document.addEventListener('visibilitychange', function () { + if (document.visibilityState === 'hidden') { + document.title = '爱我' + } else { + document.title = '恨我' + } +}) +``` + +**用途**: + +- 动画,视频,音频都可以在页面显示时打开,在页面隐藏时关闭 +- 完成登陆后,无刷新自动同步其他页面的登录状态 + +```js +// 视频暂停或播放 +document.addEventListener('visibilitychange', function () { + if (document.visibilityState === 'hidden') { + video.pause() + } else if (document.visibilityState === 'visible') { + video.play() + } +}) +``` + +- tips:页面可见性 API 对于节省资源和提高性能特别有用,它使页面在文档不可见时避免执行不必要的任务。 +- [Page Visibility(页面可见性)](https://developer.mozilla.org/zh-CN/docs/Web/API/Page_Visibility_API) +- [Page Visibility API 教程](http://www.ruanyifeng.com/blog/2018/10/page_visibility_api.html) + +### 说一下 HTML5 Drag And Drop API + +> **HTML 拖放(Drag and Drop)**接口使应用程序能够在浏览器中使用拖放功能。例如,用户可使用鼠标选择可拖拽(draggable)元素,将元素拖拽到可放置(droppable)元素,并释放鼠标按钮以放置这些元素。 + +| Event | Description | +| --------- | ---------------------------------------------------------------------------------------------- | +| Drag | 每次拖动对象时移动鼠标时,它都会激发。事件主体是被拖放元素,在正在拖放被拖放元素时触发。 | +| Dragstart | 当用户开始拖动对象时触发。事件主体是被拖放元素,在开始拖放被拖放元素时触发。 | +| Dragenter | 当用户将鼠标光标移到目标元素上时,它将激发。事件主体是目标元素,在被拖放元素进入某元素时触发。 | +| Dragover | 当鼠标移到某个元素上时触发此事件。事件主体是目标元素,在被拖放在某元素内移动时触发。 | +| Dragleave | 当鼠标离开元素时触发此事件。事件主体是目标元素,在被拖放元素移出目标元素是触发。 | +| Drop | 拖放操作结束时触发。事件主体是目标元素,在目标元素完全接受被拖放元素时触发。 | +| Dragend | 当用户释放鼠标按钮以完成拖动操作时触发。事件主体是被拖放元素,在整个拖放操作结束时触发 | + +[draggable](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/draggable) 是可枚举的属性指示该元素是否可以拖动,用于标识元素是否允许使用 [HTML 拖放 API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API) + +```html +
    + + +``` + +- [HTML Drag and Drop API](https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_Drag_and_Drop_API) +- [确定从 Dragenter 和 Dragover 事件中拖动的内容](https://stackoverflow.com/questions/11065803/determine-what-is-being-dragged-from-dragenter-dragover-events) +- [触摸屏设备上的 HTML5 Drag and Drop API](https://stackoverflow.com/questions/3382393/html5-drag-and-drop-api-on-touch-screen-devices) +- [HTML5 在窗口间 drag and drop](https://stackoverflow.com/questions/3694631/html5-drag-and-drop-between-windows) + +### 其他 HTML5 API + +#### document.querySelector() 和 document.querySelectorAll() + +- `querySelector()`:根据 css 选择器返回第一个匹配的元素,如果没有匹配返回 null +- `querySelectorAll()`:方法返回文档中匹配指定 CSS 选择器的所有元素,返回 NodeList 对象。如果 querySelectorAll 没有匹配的内容返回的是一个空数组。 + +#### classList + +- 控制 CSS 的 增、删、切换、是否存在某个类 + +```js +ele.classList.add('addClass') +ele.classList.remove('removeClass') +ele.classList.toggle('toggleClass') +ele.classList.contains('containsClass') +``` + +#### contextMenu + +- 它并不会替换原有的右键菜单,而是将你的自定义右键菜单添加到浏览器的右键菜单里 + +```html + + +``` + +你也可以阻止它,显示自己自定义的菜单 + +```js +menu.addEventListener('contextmenu', function (e) { + e.preventDefault() + // ... +}) +``` + +- [如何为您的 Web 应用程序创建自定义上下文菜单](https://dev.to/iamafro/how-to-create-a-custom-context-menu--5d7p) + +#### dataset + +- 通过 [`dataset`](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/dataset) 可以方便的获取或设置 `data-*` 自定义数据属性集 + +```html +
    + lorem +
    + +``` + +#### tabindex + +- `tabindex` 属性规定当使用 "tab" 键进行导航时元素的顺序。 +- 在 HTML4.01 中,tabindex 属性可用于:``,``,`