我的css世界

2,201 阅读36分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

传送门——我的第一篇文章: 面试不面试,你都必须得掌握的vue知识

前言

  大家好,我是前端贰货道士。上个月抽空整理了下css,融合css世界这本书和大佬关于CSS世界的思考,加上自己的实践、思考及扩展构建了属于我的css世界观。为了这次活动,我可是下了血本了,把这两个月来未更新完的存稿都拿出来凑数了,哈哈哈。文章比较长,相信大家耐心看完定会有所收货

  因为是自己的理解,所以难免会出现错误。如果大家发现了错误,或者有些问题需要交流,欢迎在评论区下留言。由于最近项目加急,还有很多事情需要处理,剩下的部分内容会在后续抽空更完,在此向大家说声抱歉。有兴趣继续读下去的朋友们可以先收藏吃灰,哈哈哈。如果本篇文章对您有帮助,烦请大家一键三连哦, 蟹蟹大家~

1. css进阶之绝对定位

  • absolute的流体特性:
 <!-- 绝对定位的流体特性 -->
<div style="position:relative;height: 100px;background: yellow;margin: 20px;">
  <div style="position: absolute;background: #f34413;left: 0;right: 0">我是水平流</div>
</div>
<div style="position:relative;height: 100px;background: yellow;margin: 20px;" 
  <div style="position: absolute;background: #f34413;top: 0;bottom: 0">我是垂直流</div>
</div>
<div style="position:relative;height: 100px;background: yellow;margin: 20px;">
   <div style="position: absolute;background: #f34413;left: 10px;right:10px;top: 10px;bottom: 10px">我是水平垂直流</div>
</div>

image.png

  • absolute的包裹性:
<div style="position:relative;height: 100px;background: yellow;margin: 20px;">
	<div style="position: absolute;background: #f34413;left: 0;">包裹性</div>
</div>

image.png

  • (重点) absolute元素实现水平垂直居中:
1.使用absolute绝对定位的流体特性水平垂直居中:

<div class="father">
    <div class="son"></div>
</div>

<style type="text/css">
.father {
    width: 400px;
    height: 400px;
    background: yellow;
    position: relative;
}
.son {
    width: 200px;
    height: 100px;
    background: green;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin: auto;
}
</style>

2.使用transform属性实现元素的水平垂直居中:

<div class="father">
    <div class="son"></div>
</div>
 
<style type="text/css">
.father{
    width: 400px;
    height: 400px;
    background: yellow;
    position: relative;
}
.son{
    width: 200px;
    height: 100px;
    background: green;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
}
</style>
  • css知识点(扩展总结):
1. html中换行得到的各行文字/字母/数字是不同的单词;
2. 在html中,对写在一行上的每个汉字视为一个单词,对一行上连着的一串```英文/数字```看作为一个单词; 
3. 一行可以放多个单词,如果发现增加一个单词,导致这行会装不下时,就会另起一行展示这个单词。
4. 当然这个单词可能会超过父容器的最大宽度,可以使用```word-break: break-all```对英文和字母强制换行,使使所有单词都
   在这个最大宽度之内;
5. 但是如果想让所有单词一行展示(不管是否超过父容器最大宽度),可以使用```white-space:nowrap```强制文本内容不换行; 
  • 绝对定位脱离文档流的特性(扩展总结):

  绝对定位元素会脱离文档流,不占据其他文档的空间,可以将其看作是位于平行于文档流的上方空间。如果元素设置了绝对定位,且未设置topbottomleftright的值,它就会按照dom结构有序排列,且悬浮于页面上方;如果元素设置了绝对定位,且设置了上下左右的值,则根据定位的位置进行布局。文档流的左上角坐标可看作是(0,0),因此可以使用topbottomleftright进行绝对定位:

<div style="position: relative">
  我是包含块
  <div style="position: absolute">我是绝对定位元素</div>
</div>

image.png

<div style="position: relative">
  我是包含块
  <div style="position: absolute">我是绝对定位元素</div>
  <div>1111111111</div>
</div>

image.png

  • absolute和overflow(重点):

  overflow: hidden与绝对定位元素之间的花火:如果overflow不是定位元素,同时绝对定位元素和overflow容器之间也没有定位元素,则overflow无法对absolute元素进行裁切。

<!-- html作为定位元素 -->
<div class="box">
    <img src="./小和尚.jpg" /> 	
</div>

<!-- overflow父元素是定位元素,跟html做定位元素同理 -->
<div style="position: relative;">
    <div class="box">
        <img src="./小和尚.jpg" /> 	
    </div>
</div>

<!-- overflow元素本身是定位元素 -->
<div class="box" style="position: relative;">
    <img src="./小和尚.jpg" /> 	
</div>

<!-- overflow元素与绝对定位元素之间有定位元素 -->
<div class="box" style="position: relative;">
    <div style="position: relative;">
        <img src="./小和尚.jpg" />
    </div> 	
</div>

<style>
.box {
    width: 80px;
    height: 120px;
    overflow: hidden;
    background: yellow;
    margin: 10px;
}
img {
    position: absolute;
    width: 100px;
    height: 100px;
}
</style>

image.png

  (重点) 如果父级没有设置相对定位,则绝对定位的元素不会受父级中overflow的auto和scroll属性影响,即使绝对定位元素宽高大于overflow元素,也不会出现滚动条。利用绝对定位的这个特性,可以实现将元素固定到顶部的效果,且该元素不会随着滚动条的滚动而滚动。如果有对父级设置相对定位,并设置oveflow:auto,则绝对定位的图片宽高会跟随父级的宽度(整个容器的宽度减去滚动条的宽度)进行等比例缩放,并出现如下图所示的滚动条。

<div class="box">
    <el-image style="position: absolute" :src="require('./1.png')"></el-image>
</div>

<style>
.box {
  width: 300px;
  height: 200px;
  overflow: auto;
  background: yellow;
  position: relative;
}
</style>

                image.png

  • (重点) 内联元素无法设置宽高,它的宽高是由内容文字撑开的。且因为其默认是水平排列的,因此对于marginpadding, 它只对水平方向设置的值有效,对垂直方向设置的值无效。而设置了绝对定位的内联元素,会转换为块级元素,或者直接将其转换为行内块元素或者块级元素,才可以设置宽高。

  • (重点) clip属性与绝对定位/固定定位元素的爱恨情仇

    clip属性只在绝对定位固定定位元素上生效, 对其他元素无效, 因此clip属性必须与绝对定位或者固定定位元素搭配使用。

<el-image class="image" :src="require('./1.png')"></el-image>

<style>
.image {
  position: absolute;
  `截图区域大小为400px * 300px,可见区域为380px *270px`
  clip: rect(30px, 400px, 300px, 20px);
}
</style>

          image.png

image.png

    最佳可访问隐藏属性的应用:

    可访问性隐藏指的是虽然内容肉眼看不见,但是其辅助功能却能够识别。举个例子,我们需要用到一个logo图标,为了更好的SEO以及无障碍识别,我们一般会使用<h1>标签写上网站的名称,

<a href="/" class="logo">
    <h1> CSS世界 </h1>
</a>

    如果要隐藏CSS世界这几个字,通常有如下五种做法:

    (1) 使用display:none或者visibility:hidden进行隐藏;

    (2) 使用*text-indent: -9999px缩进文字;

    (3) 使用clip属性定位元素,可以将这个封装为公共css

    (4) 使用color: transparent,文本框依旧在html中,可被用户选择到,需要取消浏览器的默认事

      件,操作麻烦,故不推荐;

    (5) font-size: 0px;

  • (重点)绝对定位元素与包含块之间的传奇故事:

     在CSS的世界里,元素的大小和定位计算一直都受包含块的影响。普通元素的包含块一般是他的父容器,也就是你设置某个元素的宽度100%,那么指的是相对于父容器的宽度进行计算后得到的宽度

     (1)根元素被称作初始包含块,尺寸是浏览器可视窗口的大小;

     (2) 对于position: relative/static(默认)的元素,其包含块由其最近的块容器祖先元素决定;

     (3) 对于position: fixed的元素,其包含块初始包含块;

     (4) 对于position:absolute的元素,其包含块最近的position不为static的祖先元素决定。

  • 在父容器有padding的情况下,使用border代替top和left进行绝对定位(扩展总结):

(1) 父容器使用borderpadding,子容器采取top: 0; left: 0进行绝对定位:

<div style="position: relative; background: red; border: 20px solid red">
  我是包含块
  <div style="position: absolute; top: 0; left: 0">
    我是border绝对定位元素
  </div>
</div>

image.png

(2) 父容器使用padding,并采取给topleft赋予和父容器相同padding值的方式进行绝对定位:

<div style="position: relative; padding: 20px; background: red">
  我是包含块
  <div style="position: absolute; top: 20px; left: 20px">
    我是padding绝对定位元素
  </div>
</div>

image.png

  • (重点) 相对定位基于祖先第一个出现定位的元素(padding以外)的地方进行定位,不会影响其它元素的页面布局,层叠级别较高,同时相对定位元素的left/right/top/bottom的百分比值也是基于它的包含块(不含padding进行计算的)。相对定位还有一个值得特别注意的点是,相对定位不具备流体特性。当同侧都有值时,只保留left和top。因此对于块级元素使用margin: auto只能做到水平居中, 无法水平垂直居中。而绝对定位基于祖先第一个有定位的元素(包含padding)(当找不到该元素时,则以页面根元素为基准)进行定位。
  • 行内元素具有包裹性(自适应性),而块级元素具有流体特性(默认一行)。使用text-align布局时,可以对某个包裹器下的容器或者单独对这个容器下的文本进行处理。
  • 绝对定位元素的宽高是基于父级有定位的元素(包含元素自身的内容区域和padding区域)进行计算的。
<!-- relative定位测试 -->
<div class="container">
    <div class="">我是一个吃瓜群众</div>
    <div class="relative">relative</div>
    <div class="">我是一个吃瓜群众</div>
</div>
<style>
.container{
    width: 200px;
    height: 200px;
    background: #999999;
    padding:100px;
    border:5px solid red;
    position: relative;
}
.relative{
    width: 100px;
    height: 100px;
    background: green;
    position: relative;
    // left: 50% (相对包含块的宽度200px); 
    left: 100px;
    top: 100px;
}
.absolute{
    width: 100px;
    height: 100px;
    background: yellow;
    position: absolute;
    left: 100px;
    top: 100px;
}
</style>

          image.png

image.png

2. css进阶之content的高级用法

  • 巧用dom上的自定义属性(自定义名称)配合content:attr属性生成内容

              image.png

<div class="list">
    <div class="li" category="音乐">aaa.mp3</div>
    <div class="li" category="电影">bbb.mp4</div>
    <div class="li" category="书籍">《ccc》</div>
</div>

<style>
.li{
    line-height: 40px;
    width: 200px;
    padding-top: 40px;
    position: relative;
    background: yellowgreen;
    overflow: hidden;
    margin:10px 0;
}
.li::after{
    content: attr(category);
    position: absolute;
    top: 0;
    right: 0;
    background: yellow;	
    text-align: center;
    width: 80px;
    // translate是在X、Y轴上进行变化,此处写一个参数表示X轴
    // 或者直接使用translateX(20px)进行变换
    transform: translate(20px) rotate(45deg); 
}
</style>
  • 使用content进行计数
<div class="ctn">
    <div class="chid">计数</div>
    <div class="chid">计数</div>
    <div class="chid">计数</div>
</div>

<style type="text/css">
.ctn{
    font-size: 20px;
    color: green;
    background: yellow;
    // 在父容器上重置hello的初始值,如果不设置,则默认为0,且必须为整数(包含负数)
    // counter-reset: a b 1 c 9   添加a,b,c这3个计数器,且分别赋值为0 1 9
    counter-reset: hello 1;
}
.chid::after{
    // 计数器只有遇到counter-increment才会递增,否则永远为初始值
    content: counter(hello);
}
</style>

          image.png

<div class="ctn">
    <div class="chid">计数</div>
    <div class="chid">计数</div>
    <div class="chid">计数</div>
</div>

<style type="text/css">
.ctn{
    font-size: 20px;
    color: green;
    background: yellow;
    counter-reset: hello 1;
}
.chid::after{
    content: counter(hello);
    // counter-increment第二个参数可以省略,默认为1
    counter-increment: hello 2;
}
</style>

          image.png

<div class="ctn">
    <div class="chid">计数</div>
    <div class="chid">计数</div>
    <div class="chid">计数</div>
</div>

<style type="text/css">
.ctn{
    font-size: 20px;
    color: green;
    background: yellow;
    counter-reset: hello 1;
    counter-increment: hello 2;
}
.chid::after{
    content: counter(hello);
    counter-increment: hello 2;
}
</style>

              image.png

  • 利用counters()嵌套计数实现目录结构

              image.png

<template>
  <div>
    <h3>嵌套章节列表 - counters</h3>
    <div class="counters__reset">
      <div class="title">
        概述
        <div class="counters__reset">
          <div class="title">CSS 世界的"世界观"</div>
          <div class="title">
            世界都是创造出来的
            <div class="counters__reset">
              <div class="title">何为"流"</div>
              <div class="title">流是如何影响整个 CSS 世界的</div>
            </div>
            <div class="title">CSS 完胜 SVG 的武器—流</div>
          </div>
        </div>
      </div>
      <div class="title">
        流、元素与基本尺寸
        <div class="counters__reset">
          <div class="title">CSS 世界的“世界观</div>
          <div class="title">世界都是创造出来的</div>
          <div class="title">CSS 完胜 SVG 的武器—流</div>
        </div>
      </div>
    </div>
  </div>
</template>

<style>
.counters__reset {
  counter-reset: listNumber;
  padding-left: 20px;
  font-size: 0.2rem;
}

.title::before {
  counter-increment: listNumber;
  content: counters(listNumber, '.') '.';
  margin-right: 5px;
}
</style>

3. css进阶之display:none 与 visibility: hidden

  • display为none的元素其实可以通过label for id的方式进行点击
<form>
    <input id="hide" type="submit" style="display:none"/>
    <!--点击提交按钮,其实会触发隐藏元素输入框的点击事件-->
    <label for="hide">点击触发提交</label>
</form>
  1. display: none会影响transition的过渡动画效果,而visibility:hidden则不会;
  2. display: none会影响到计数值,原先计算为3的列表会变为2.
  • display:none与visibility: hidden的区别
<template>
  <div>
    <div class="page-warpper">
      <!--visibility: hidden的元素会占位-->
      <p>我是隐藏的子元素一</p>
      <p>我是隐藏的子元素二</p>
    </div>
    <p>我是显示的元素一</p>
  </div>
</template>

<style>
.page-warpper {
  visibility: hidden;
}
</style>

            image.png

<template>
  <div>
    <div class="page-warpper">
      <!--display: none的元素不会占位-->
      <p>我是隐藏的子元素一</p>
      <p>我是隐藏的子元素二</p>
    </div>
    <p>我是显示的元素一</p>
  </div>
</template>

<style>
.page-warpper {
  display: none;
}
</style>

            image.png

<template>
  <div>
    <div class="page-warpper">
       <!--display: none的元素作为父级时,其孩子无法通过display: block这个样式显示-->
      <p>我是隐藏的子元素一</p>
      <p style="display: block">我是隐藏的子元素二</p>
    </div>
    <p>我是显示的元素一</p>
  </div>
</template>

<style>
.page-warpper {
  display: none;
}
</style>

            image.png

<template>
  <div>
    <div class="page-warpper">
       <!--visibility: hidden的元素作为父级时,其孩子可以通过visibility: visible这个样式显示-->
      <p>我是隐藏的子元素一</p>
      <p style="visibility: visible">我是隐藏的子元素二</p>
    </div>
    <p>我是显示的元素一</p>
  </div>
</template>

<style>
.page-warpper {
  visibility: hidden;
}
</style>

            image.png

4. css进阶之border和padding

  • border的颜色可以省略。在省略的情况下,边框颜色与这个元素对应类上的color相同
<div class="filePost"></div>
 
<style>
.filePost {
  width: 76px;
  height: 76px;
  // 边框默认颜色为#ccc
  color: #ccc;
  border: 2px dashed;
  position: relative;
}
.filePost:hover {
  // hover时,边框颜色为#384edb
  color: #384edb;
}
.filePost::before,
.filePost::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.filePost::before {
  width: 20px;
  border-top: 4px solid;
}
.filePost::after {
  height: 20px;
  border-left: 4px solid;
}
</style>

默认样式

image.png

hover样式

image.png

  • (重点)border-box在块级元素上的特例

  box-sizing默认的值是content-box,我们都知道使用box-sizing:border-box可以消除padding对盒子宽度带来的影响。但有一种情况例外,那就是当padding的值足够大时。比如2 * padding的值大于width的值时,就会以padding的总宽度作为盒子的宽度。

<template>
  <!--虽然此时的真实宽度已经变为了82px,content内容为0,但是其实它的主体区域还是由padding撑开的-->
  <!--显示123的原因是因为分词的缘故,这是一个单词,所以虽然宽度不够,还是必须得在一行显示-->
  <!--但是如果此时再加上word-break,就会由于content内容区域放不下而自动换行,一行只显示一个数字-->
  <div class="box">123</div>
</template>

<style>
.box {
  display: block;
  width: 80px;
  padding: 0 41px;
  box-sizing: border-box;
  /* word-break: break-all; */
}
</style>

          image.png

                image.png

  • 内联元素在padding上的应用:增加文字点击区域

  padding会同时影响内联元素的水平和垂直方向,padding的值不能为负数,padding的百分比无论在水平或者是垂直方向上,都是基于父容器的宽度进行计算的。

5. css进阶之margin的特殊应用

  需要特别注意,因为clear:both针对块级元素生效,所以父级清除浮动添加的伪元素必须得是block块级元素。默认的伪元素属于行内元素,且必须要设置content属性。此外还有一点需要特别注意的是,margin样式是无法继承父级的。

  • (重点) margin的合并与坍塌

   margin与BFC的碰撞

   margin合并与塌陷的解决方案

   注意事项:

1. `margin的合并与塌陷只发生在块级元素上,行内和行内块元素不会发生`2. `margin合并/坍塌发生的条件`:
(1) 相邻兄弟(不存在空元素)之间进行margin合并(合并,第一个盒子margin-bottom,第二个盒子margin-top);
(2) 父级和第一个/最后一个子元素(坍塌,垂直方向, 同为margin-top);
(3) 空块级元素与其余相邻元素的margin合并(第一种情况的特殊形式,合并,垂直方向上);

3. `如何解决margin合并/塌陷`:
(1) 将父级设置为BFC;
(2) 给父级添加边框;
(3) 将父级转换为行内块元素;

4. 合并生效规则:`正正取最大的那个margin,负负取最负的那个margin,正负就相加,取第二个盒子的margin。`
  • 使用margin: auto分配剩余空间
<div class="father">
    <div class="son"></div>
</div>

<style>
.father{
    height: 400px;
    background: yellow;
}
.son{
    width: 200px;
    margin-right: 100px;
    margin-left: auto;
    height: 200px;
    background: red;
}
</style>

image.png

<!--固定在最右侧-->
<div class="father">
    <div class="son"></div>
</div>

<style>
.father{
    height: 400px;
    background: yellow;
}
.son{
    width: 200px;
    margin-left: auto;
    height: 200px;
    background: red;
}
</style>
  • (重点) 块级元素的水平垂直居中(margin:auto管理容器的剩余空间)
1. 父级使用flex布局,子级使用margin: auto 或者 flex的垂直居中即可完成布局(`在flex布局的BFC中,子元
   素若有设置margin:auto,则任何空闲的空间都会自动分配到该方向的margin中`);
   (`如果有设置优先级更高的margin: auto,则父元素的justify-content或者子元素align-self不会生效`)
2. 父级使用相对定位,子级使用绝对定位,使用margin: auto进行水平垂直居中;
3. 父级使用相对定位,子级使用绝对定位,使用top和lefttransform进行水平垂直居中;

  扩展(重点):块级元素使用margin: auto不能垂直居中: margin-leftmargin-right都为auto的时候,则表示他们的值相等,值得计算为剩余空间的一半,所以会水平居中。而当margin-topmargin-bottomauto的时候,则表示他们的值是0,所以无法完成垂直方向的居中。

6. css进阶之line-height与vertical-align的理解

  • 对图标设置vertical-align: middle或者height: 1ex(相对于当前字体的x-height长度,也就是字母X的高度)可以实现文字和图标的居中对齐

  • (重点) vertical-align可以设置数值,而且能支持负值。当vertical-align的值为0时,表现为vertical-align:baseline,即和X的底部对齐。通过这个特性,我们可以修改vertical-align的值进行对齐。而vertical-align百分比的计算规则是依据line-height的大小计算得来的。

  • 内联元素中存在的行框盒子的高度只与line-height有关,由这一行内联元素最大的line-height值所决定,line-height的计算公式是 line-height = font-size + 上半行距 + 下半行距

  • line-height只能间接影响块级元素的高度,任何直接包含在块容器元素内(而不是内联元素内)的文本都必须被视为匿名内联元素。匿名内联元素会继承父容器的line-height,生成行框盒子。每一行文本就是一个行框盒子,从而撑开块级元素的高度。

  • (重点) line-height的属性值:line-height的默认值是normal, 它支持数值,百分比和具体长度值。数值和百分比值的计算方式是完全相同的,都是font-size * 长度/百分比,代表字体大小的倍数向下取整。比如14 * 1.4  = 19.6 = 19px,注意不是四舍五入,是向下取整的。但是在这两种方法的取舍上,我们通常会使用数值,这是由于它们的继承方式不同导致。使用数值的方法:本身的font-size * 数值,使用百分比的方法:继承来的line-height * 百分比。

  • (重点) 幽灵空白节点的产生及解决方案:

     a. 产生:

     (1) 空的行内块元素: 换行也只在最后一行会产生一个幽灵空白节点

     (2) 有内容的内联元素换行会产生n个幽灵空白节点(n为行数)

     b. 解决:

     1. 给包裹元素添加font-size: 0, 再重新设置子级的字体大小即可。

     2. 将幽灵节点设置为块级元素。

  • (幽灵节点的运用) absolute与text-align:
image.png

     text-align是文本对齐方式,针对的是内联元素,而absolute具有块状化元素的特性。

<div style="text-align: center;">
    <span style="position: absolute;">hello</span>
</div>

          image.png

  absolute元素似乎受到text-align的影响处于容器中偏右的位置,那么text-align真的可以影响块元素吗?答案是否定的。text-align影响的依旧是内联元素,只是这个内联元素是你看不到“幽灵空白节点”。由于span标签原来是个内联元素,因此在该元素前面生成了一个幽灵空白节点,这个节点默认是个内联元素,受到了text-align:center的感化,跑到了div的中间,虽然不占位置,但占据了一个看不见的空间,而这个看不见的空间对后面的“无依赖绝对定位”元素产生了影响,这个absolute元素就乖乖的跟在后边了。因此absolute元素并不是直接和text-align发生关系!

7. css进阶之无依赖的fixed固定定位(有点类似绝对定位)

  前文已经提及过,fixed固定定位的包含块根元素,因此它的top/bottom/left/right也是根据浏览器的可视窗口进行定位的。

<div class="container">
    <span>随便说两句</span>
    <div class="fixed"></div>
</div>

<style>
.container {
    box-sizing: border-box;
    width: 400px;
    height: 400px;
    background: #999999;
    padding: 100px;
    border: 5px solid red;
}

.fixed {
    width: 100px;
    height: 100px;
    background: green;
    position: fixed;
}
</style>

         image.png

.fixed的下方加一个 top: 100px的样式

         image.png

<div class="container">
    <span>随便说两句</span>
    <div class="fixed"></div>
    <div>12321312</div>
</div>

<style>
.container {
    box-sizing: border-box;
    width: 400px;
    height: 400px;
    background: #999999;
    padding: 100px;
    border: 5px solid red;
}
.fixed {
    width: 100px;
    height: 100px;
    background: green;
    position: fixed;
}
</style>

         image.png

  (重点) 使用固定定位fixed做遮罩:

  1. 需要提供一个水平垂直居中固定定位的遮罩绝对定位的弹框

<div class="fixed-warpper">
    <div class="dialog-warpper">我是弹窗</div>
</div>

<style>
.fixed-warpper,
.dialog-warpper {
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  margin: auto;
}

.fixed-warpper {
  position: fixed;
  background: rgba(0, 0, 0, 0.5);
}

.dialog-warpper {
  position: absolute;
  width: 40%;
  height: 30%;
  background: #fff;
}
</style>

  (重点) 不受控制的fixed元素: 当元素祖先的 transform 属性非 none 时,定位容器由视口改为该祖先。

8. css进阶之文本处理

  • ex、em与rem:

    (1) ex是字母X的高度,font-size的值越大,ex越大;

    (2) emfont-size有关,但这个单位受当前上下文font-size影响,很不稳定。

<span>hello</span>
<span>world</span>

<style type="text/css">
span {
    font-size: 2em;
    margin: 0 1em;
}
</style>

                  image.png

font-size:2em = 2 * 浏览器默认的font-size = 2 * 16px = 32px

margin:0 1em = 1 * font-size = 32px

  <p>
    道士:欢迎进入我的CSS世界!欢迎进入我的CSS世界!欢迎进入我的CSS世界!欢迎进入我的CSS世界!欢迎进入我的CSS世界!欢迎进入我的CSS世界!
  </p>
  
  `text-indent`仅对第一行内联盒子内容有效
  
  p {
    padding-left: 3em;
    text-indent: -3em;
    width: 300px;
  }

             image.png

    (3) rem: 移动端常用响应式布局方案,只和根元素font-size大小有关。

  • font-size的冷门属性:

    (1) 相对尺寸关键字: 相对当前元素的font-size进行计算,larger表示比当前元素大一点,

smaller表示比当前元素小一点,分别对应bigsmall标签

    (2) 绝对尺寸关键字:浏览器设置的字号(非当前元素的字体大小)影响, 有非常大,很大,大,

(medium),小,很小,非常小这种关键字。选择范围少,不同浏览器文字大小不一,不推荐使用。

  • letter-spacing用于调整字符间距,word-spacing用于调整空格间隙
  • white-space用法解析:
<div class="normal">合并空白字符和换行符</div>
<div class="pre">空白    字符不合 并,并且只有在有换行符的地方
换行
</div>
<div class="nowrap">合并空     白字符,但是不能
换行,换行符用空格
代替
</div>
<div class="pre-wrap">空白字符  不    合并,允许自动换行和
手动
换行
</div>
<div class="pre-line">空白字符     合并,允许自动换行和
手动
换行
</div>
 
<style>
div {
    width: 8em;
    margin: 40px 0;
}
.normal {
    white-space: normal;
}
.pre {
    white-space: pre;
}
.nowrap {
    white-space: nowrap;
}
.pre-wrap {
    white-space: pre-wrap;
}
.pre-line {
    white-space: pre-line;
}
</style>

        image.png

  • text-transform: uppercase/lowercase, 这个属性主要用于控制字符的大小写,会自动转换为大/小写,text-align: justify用于控制两端对齐。

9. css进阶之float浮动

  • 浮动元素的参考物体:

  浮动元素参考的是离他最近的行框盒子。如果没有可以参考的行框盒子,浮动元素自带一个可以参考的浮动锚点(是float元素所在流中的一个,也是一个空的内联元素)。

<!-- 验证浮动参考是离他最近的行框盒子,此处有3个行框盒子 -->
<div style="width: 200px;text-align: justify;background: yellow">
    <span style="float: right;color:blue">更多</span>
    <span>这里有很多文字,且要超出一行且要超出一行且要超出一行</span>
</div>

                image.png

<!-- 测试浮动参考 -->
<div style="width: 200px;text-align: justify;background: yellow">
    <span>这里有很多文字,且要超出一行且要超出一行且要超出一行</span>
    <span style="float: right;color:blue">更多</span>
</div>

                image.png

<!-- 测试浮动参考 -->
<div style="width: 200px; text-align: justify; background: yellow">
    <span>这里有很多文字,且要超出一行且要超出一行且要超出一行</span>
    <span style="float: left; color: blue">更多</span>
</div>

                image.png

  • 清浮动:浮动真的被清除了吗(注意父容器高度)?

  使用clear清除浮动,其实并未清除浮动,因为浮动元素还在。那么clear到底做了什么呢? 元素盒子的边不能和前面的浮动元素相邻, 这也是为什么我们清除浮动伪元素使用after而不是before的原因。clear并没有改变任何浮动元素的特性,浮动元素依旧是那个浮动元素,不管你清不清,他还是在那边,浮着。

<!-- 因为都是浮动元素,所以父元素div的高度为0 -->
<div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
</div>

<style>
.li {
    float: left;
    margin: 10px;
    width: 40px;
    height: 40px;
    background: yellow
}
.li:nth-of-type(3){
    clear: both;
}
</style>

        image.png

<div class="clearfix">
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
    <div class="li"></div>
</div>

<style>
.li {
    float: left;
    margin: 10px;
    width: 40px;
    height: 40px;
    background: yellow
}
.li:nth-of-type(3) {
    clear: both;
}
.clearfix::after {
    content: '';
    // 因为伪元素默认为行内元素(inline),而clear: both只对块级元素生效
    display: block;
    clear: both;
}
</style>

image.png

10. (重点)善用js和伪元素控制网页的样式

当使用last-child时,发现父级嵌套太多,导致很难使用CSS选择器,此时没必要纠结非要使用css去解决这个问题。可以使用js
判断当前是否为最后一个节点,然后给它添加动态样式,去重置它的样式就好了。

<div :class="['step-container', isLastChild(item) && 'disbaled']">
    <span class="step-warpper">{{ item.step }}</span>
</div>

.disbaled::after {
  display: none;
}

11. 穿透element组件的样式

  当发现element组件的样式无法穿透时,需要考虑当前组件是否和页面组件处于同一层级。如果是处于同一层级,使用组件自带的popper-class给类名,从而达到修改样式的目的。

12. 修改浏览器的滚动条样式

  效果如上所示:

::v-deep {
  ::-webkit-scrollbar {
    // 修改滚动条的宽度
    width: 6px;
  }
  ::-webkit-scrollbar-thumb {
    // 修改滚动条的背景颜色
    background: $color-separator;
  }
}

13. 箭头上下翻转的css样式

/* 旋转加平滑过渡实现动画效果 */ 
.rotate-down { 
  transform: rotate(0deg); 
  transition: all 0.2s ease 0s; 
}

.rotate-up { 
  transform: rotate(-180deg); 
  transition: all 0.2s ease 0s; 
}

14. 伪元素实现正三角

.select-content:before { 
  content: ''; 
  height:0px; 
  width:0px; 
  border-bottom: 8px solid #dcdce0; 
  border-left:8px solid transparent; 
  border-right:8px solid transparent; 
}

15. 图片添加背景颜色

  效果如下所示:

image.png

// 给包裹图片的div父盒子增加背景颜色
.image-warpper {
  transformscale(1);
  background: #ccc; 
  .el-image { 
    mix-blend-mode: multiply; 
   } 
 }

16. 修改el-checkbox的大小和样式

::v-deep {
    .el-checkbox__inner {
      width: 18px;
      height: 18px;
      border: 1px solid #e6e6e6;
      border-radius: 2px;
    }
    //重置√的样式
    .el-checkbox__inner::after {
      height: 10px;
      width: 6px;
    }
}

17. 相邻选择器

.row-line {
  margin: 0 -10px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  & + .row-line {
    //相当于为除第一个row-line类以外的所有row-line类添加上边框样式
    border-top: 1px solid #ebeef5;
  }
}

18. el-tabs下划线添加左右padding

  效果如下所示:

image.png

//公共样式
.padding-tabs {
  .el-tabs__item{
     padding5px; //用于控制不同tab之前的间距
  }
  .el-tabs__item::before,
  .el-tabs__item::after {
    content: ' ';
    display: inline-block; //伪元素相当于span标签,是内联元素,需要转换为行内块元素
    width: 15px; //相当于在每个tab文字前后增加了长度为15px的隐藏文字
  }
}

19. 解决google浏览器默认最小字体为12px的样式问题

.time {
  font-size: 12px;
  zoom: 0.9;
}

20. 字符串长度超过指定宽度自动换行(word-break: break-all和break-word的区别)

// 传送门:http://t.zoukankan.com/tu-0718-p-10006304.html
// 对英文和数字才生效
word-break: break-all;  // 超过宽度就直接另起一行
word-break: break-word; // 超过宽度,整个单词另起一行

21. 去除el-form必填校验前面的星号

.el-form-item.is-required .el-form-item__label:before {
  content: '';
}

22. 遮罩层的制作

.mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 3;
}

23. 图片自适应布局(一行N个 + 方形图片)

  效果如下所示:

image.png
```核心思想:
1.使用el-row和el-col排列布局,然后使用属性选择器重构布局样式;
2.将每个el-checkbox的宽度设置为100%,让容器撑开;
3.给图片包裹一个外层容器,使用padding-top: 100%撑开,给容器相对定位,再给图片绝对定位即可
4.使用@click.prevent是为了阻止它点击选中checkbox,这样就可以做到点击图片出现详情,点击单选框进行勾选
5.(重点)使用user-select: text对checkbox进行样式穿透,使得checkbox里嵌套的文字(默认不可复制)可以被复制```

<template>
  <div class="card-warpper" v-loading="tableLoading">
    <div class="operation-warpper flex-middle">
      <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange"></el-checkbox>
      <el-button class="ml10" @click="changeFolder">{{ $t('page.folder.change') }}</el-button>
      <el-button class="download-button" @click="download">{{ $t('page.folder.download') }}</el-button>
      <el-button @click="del">{{ $t('page.folder.del') }}</el-button>
    </div>
    <el-row>
      <el-checkbox-group v-model="checkedList" @change="handleCheckedChange">
        <el-col :span="4.8" v-for="img in tableData" :key="img.id">
          <div class="checkbox-img-col">
            <el-checkbox :label="img" class="checkout-item">
              <div class="image-warpper">
                <el-image @click.prevent="showDialog" :src="getUrl(img)"></el-image>
              </div>
              <div class="name text-cut">{{ getName(img) }}</div>
              <div class="description-warpper">
                <span class="storage">{{ getStorage(img) }}</span>
                <span>{{ getSize(img) }}</span>
              </div>
            </el-checkbox>
          </div>
        </el-col>
      </el-checkbox-group>
    </el-row>
    <base-pagination
      class="page"
      layout="prev, pager, next, sizes"
      :page="tablePage"
      :pageSizes="pageSizes"
      @size-change="sizeChange"
      @current-change="pageChange"
    ></base-pagination>
  </div>
</template>

<script>
import { avueCrud } from '@/mixins'
import imageApi from '@/api/imageApi'
import basePagination from '@/components/avue/crud/src/basePagination'

export default {
  components: { basePagination },
  mixins: [
    avueCrud({
      getList: imageApi.getPictureList
    })
  ],
  data() {
    return {
      checkedList: [],
      checkAll: false,
      // 这个全选和半选应为计算属性
      isIndeterminate: false,
      pageSizes: [10, 20, 50]
    }
  },
  props: {
    folderId: {
      type: Number,
      default: 0
    }
  },
  methods: {
    handleCheckedChange() {},
    getUrl(data) {
      return (
        data?.path ||
        'https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPng4e0db7b892b3c6abd7c1e48da9a018d38e0f30138b049fe081e28ad06d47dc51'
      )
    },
    getName(data) {
      return data?.name || '前端测试数据前端测试数据前端测试数据前端测试数据'
    },
    getStorage(data) {
      return '1 MB' || `${data?.storage} MB`
    },
    getSize(data) {
      return '1200 * 1200 px' || `${data?.size} px`
    },
    handleCheckAllChange() {},
    changeFolder() {},
    download() {},
    del() {},
    showDialog() {
    }
  }
}
</script>

<style lang="scss" scoped>
.card-warpper {
  font-size: 14px;
  ::v-deep {
    .el-checkbox__label {
      width: 100%;
      user-select: text;
    }
  }
  .operation-warpper {
    margin-top: 20px;
    .download-button {
      margin: 0 10px 0 20px;
    }
  }
  .page {
    text-align: right;
    margin-top: 20px;
  }

  .el-col[class*='el-col-4.8'] {
    width: calc(100% / 24 * 4.8);
    background: #fff;
  }

  .checkbox-img-col {
    margin-top: 20px;
    .checkout-item {
      width: 100%;
      ::v-deep {
        .el-checkbox__input {
          position: absolute;
          left: 20px;
          top: 10px;
          z-index: 1;
        }
      }
      .image-warpper {
        padding-top: 100%;
        position: relative;
        .el-image {
          border: 1px solid #ebebeb;
          width: 100%;
          height: 100%;
          position: absolute;
          top: 0;
          left: 0;
        }
      }
      .name {
        margin: 14px 0;
      }
      .text-cut {
        width: 90%;
      }
      .description-warpper {
        color: $color-icon;
        .storage {
          margin-right: 15px;
        }
      }
    }
  }
}
</style>

24. flex布局中的order属性

  order属性只在flex布局中生效,根据order的大小进行排序。order值小的在前方显示,order值大的在后方显示。

25. (重点) 关于nth-child中的n是从0还是1开始

  nth-child描述的是兄弟节点,如果nth-child前面的类,描述的不是兄弟节点,则不会生效。 如果vue中的template模板循环了多个父级div,然后在父级div下,嵌套了多个子节点, 分别对应类AB, C。此时, 多个A就不为兄弟节点,而多个父级div才是兄弟节点。

<ul class="list">
    <li>索引为0,这是父元素ul的第一个子元素li</li>
    <li>索引为1,这是父元素ul的第二个子元素li</li>
    <li>索引为2,这是父元素ul的第三个子元素li</li>
    <li>索引为3,这是父元素ul的第四个子元素li</li>
    <li>索引为4,这是父元素ul的第五个子元素li</li>
    <li>索引为5,这是父元素ul的第六个子元素li</li>
    <li>索引为6,这是父元素ul的第七个子元素li</li>
    <li>索引为7,这是父元素ul的第八个子元素li</li>
    <li>索引为8,这是父元素ul的第九个子元素li</li>
    <li>索引为9,这是父元素ul的第十个子元素li</li>
</ul>
`(重点) nth-child属性是针对父级来计算的, 比如li:nth-child(1)是该css父级的第一个子元素并且是li才显示`
`小插曲:直接输入正整数代替n,此种情况默认是n从第1个开始计数(可以将这种特殊情况归纳到第一种情况中)`

li:nth-child(1) {
  color: red;
}

              image.png

`第一种情况,如果括号中为n, 2n,3n这种类型,整个结果就必须大于0,也就是n从1开始`

.list > li:nth-child(3n) {
  color: blue;
}

               image.png

`第二种情况,如果括号中为an +b这种类型,只要an + b的值大于0,n就从0开始计数`

.list > li:nth-child(3n + 1) {
  color: green;
}

               image.png

  第三个el-col下的按钮布局:

::v-deep {
  .el-col:nth-child(3) .el-button--gray {
    margin-top: 10px;
  }
}

26. 使用text-align: justify实现英文的两端对齐效果

27. 元素hover或者focus样式的调试小技巧

  F12打开调试工具,选中当前需要调试的dom。选中样式tab栏,为当前需要hover或者focus的元素选中hoverfocus样式,就可以愉快地调整样式啦。

     image.png

28. 爬坑我知道了的引导页样式

  话不多说,先上效果图:

image.png

`核心思想是使用element UI的模态框`

`坑1: 模态框需要初始化,去标题、去padding、去头部、去背景及去阴影`

`
 设置背景的三种方法:
 
 方法一:
 
 .background {
   background: #666;
   opacity: 0.5;
 }

 方法二:
 
 .background {
   background: rgba($color: #666, $alpha: 0.5);
 }
 
  方法三:
  
  .background {
    background: rgba(0, 0, 0, 0.5);
  }
`

::v-deep {
  .el-dialog .el-dialog__title {
    visibility: hidden;
  }
  
  .el-dialog .el-dialog__header {
    display: none;
  }
  
  .el-dialog {
    background: transparent;
    box-shadow: none;
  }
  
  .el-dialog__body {
    padding: 0;
  }
}

`坑2: 模态框需要给100%的宽度,整个覆盖到页面上`
width="100%"

`坑3:由于该页面有个header(被我隐藏掉了),因此模态框需要给一个margin-top值`
style="margin-top: calc(130px - 15vh)"

`坑4:对于文字要写在切图里面的,比如上述效果图中的文字需要写在白色说明切图框中,需要给父容器添加一个背景图`
`然后在背景图中,按照要求填入文字和按钮`

<div class="first-mask">选择想要组合的产品</div>

.first-mask,
.second-mask,
.third-mask {
  color: $subMenuBg;
  text-align: center;
  background-position: center center;
}
  
.first-mask {
  background-image: url('./mask1.png');
  min-width: 188px;
  height: 128px;
  padding-top: 87px;
}

29. background-clip: text用文字的范围来裁剪背景图片,实现文本特效

37FIFM[RTQZV3]P71DF0J}F.png

ROSTK11PHJ@W`G~MHGBDM7.png

30. 关于最近很火的网站置灰样式

  • 基础版:全站置灰
html { 
  filter: grayscale(.95); 
  -webkit-filter: grayscale(.95); 
}
  • 进阶版:首页置灰,翻页恢复样式

  在讨论这个进阶需求之前,有三个样式需要明细:

    a. filterbackdrop-filter的比较:

    (1) filter:该属性将模糊或颜色偏移等图形效果应用于元素。

    (2) backdrop-filter: 该属性可以让你为一个元素后面区域添加图形效果(如模糊或颜色偏移)。 它适用于元素背后的所有元素,为了看到效果,必须使元素或其背景至少部分透明。

<div class="bg">
  <div>Normal</div>
  <div class="g-filter">filter</div>
  <div class="g-backdrop-filter">backdrop-filter</div>
</div>

.bg {
    background: url(image.png);
    
    & > div {
        width: 300px;
        height: 200px;
        background: rgba(255, 255, 255, .7);
    }
    .g-filter {
        filter: blur(6px);
    }
    .g-backdrop-filter {
        backdrop-filter: blur(6px);
    }
}

效果浏览:

image.png

    b. inset属性:该属性只用于定位元素中,IE不支持该属性

`1. 等同于 top: 0; right: 0; bottom: 0; left: 0;`
inset: 0; 

`2. 等同于 top: 1px; right: 2px; bottom: 1px; left: 2px;`
inset: 1px 2px; 

`3. 等同于 top: 1px; right: 2px; bottom: 3px; left: 2px;`
inset: 1px 2px 3px; 

`4. 等同于 top: 1px; right: 2px; bottom: 3px; left: 4px;`
inset: 1px 2px 3px 4px; 

    c. pointer-events: none: 这个属性很有趣,被赋予该属性的元素就像透明白纸,看得见却摸不着。如果一个元素添加了这个属性,那么该元素上的所有事件都无效,常用于遮罩穿透上,使得被遮罩覆盖的元素可以操作。

具体实现:

<template>
  <div class="home-warpper">
    <div class="home">
      <div>欢迎登陆</div>
      <el-button class="mt20" @click="clickHandler">click me</el-button>
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    clickHandler() {
      console.log('click me')
    }
  }
}
</script>

<style>
.home-warpper {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: auto;
}
.home-warpper::before {
  content: '';
  position: absolute;
  inset: 0;
  backdrop-filter: grayscale(95%);
  z-index: 2;
  height: 100vh;
  pointer-events: none;
}
.home {
  background: red;
  padding-top: calc(40vh - 25px) !important;
  font-size: 25px;
  text-align: center;
  height: 200vh;
}
</style>

效果浏览:

image.png image.png

31. z-index生效的前置条件: 在父级/当前元素上设置了定位属性, 父级设置了display:flex, 或者在当前元素上设置了transformopacity属性。可以这么理解:z-index的值默认为auto,可以被视为0。而设置了这些属性的元素,会将它们的z-index设置为1。

32. (基础) span这类行内元素需要设置display: inline-block转换成行内块元素,才能设置宽高

33. 移除el-table表头右边框

::v-deep {
  th {
    border: none;
  }
}
image.png

34. 级联选择器下拉出现小蓝点的问题解决

::v-deep {
  .el-radio__inner::after {
      transform: translate(-50%,-50%) scale(0.000001); //解决el-cascader小蓝点闪烁问题
  }
}

35. 关于webpackscssadditionalData配置

css: {
    loaderOptions: {
      // 给 sass-loader 传递选项
      sass: {
        // @/ 是 src/ 的别名
        // 所以这里假设你有 `src/variables.scss` 这个文件
        additionalData: `
            @import "~@/styles/function.scss";
            @import "~@/styles/variables.scss";
            @import "~@/styles/mixin.scss";
        `
      }
    }
}

  特别注意:

  • 全局引入的css要注意引入顺序,样式表的顺序会影响样式的优先级。通常来说,应该先引入变量文件,然后再引入其他样式文件,以确保变量在其他样式文件中可以被正确地使用。
  • 假设在全局文件中同时引入了abcd四个scss文件。虽然其他文件都能识别到在a文件中定义的scss变量,并且在其他文件中定义的与这些变量关联的css类也能够全局使用,但是在其他vue文件中却无法引入并识别这些scss变量。这是因为SCSS变量只有在编译为CSS后才会被解析和识别,而main.js中的全局CSS是在编译之前就被加载的。
  • 为解决这个问题,我们可以使用webpack中针对scssadditionalData配置。这个配置相当于在每个vue文件中都添加该配置下的所有scss文件。此时,我们可以在vue中识别并使用定义在全局的scss变量。同时,需要注意的一点是,scss变量也是有作用域的。在一个vue文件中,在scoped作用域下定义的scss变量只能在该局部作用域下使用,在全局作用域下定义的scss变量只能在该全局作用域下使用。
  • 那么问题来了,既然additionalData这么香,为什么不将所有的css文件都配置到这里面呢?前文提及,由于additionalData的机制,会为每个vue文件都添加相应的css。如果css文件很大,vue文件很多,会导致编译时间过长等各类严重影响性能的问题发生。为此,additionalData虽好,但只建议在这个配置下引入一些需要全局使用的scss变量。
  • additionalData中引入的样式相当于scoped样式,而在main.js中引入的样式,相当于全局样式(非scoped)

36. scss高级用法

1. https://zhuanlan.zhihu.com/p/354211849
2. https://www.ilaoniu.cn/articles/272
3. https://blog.csdn.net/i042416/article/details/109613068

37. 增大el-dropdown-item的可点击区域

<el-dropdown trigger="click">
  <el-button type="primary"> 上传<i class="el-icon-arrow-down el-icon--right"></i> </el-button>
  <el-dropdown-menu slot="dropdown">
    <el-dropdown-item>
      <FileUpload :files.sync="tmpFiles" ref="fileUpload" list-type="text" @updateFiles="updateFiles">
        <span class="padding"> 上传文件</span>
      </FileUpload>
    </el-dropdown-item>
    <el-dropdown-item>
      <FileUpload
        :files.sync="tmpFiles"
        ref="folderUpload"
        list-type="text"
        :isFolder="true"
        @updateFiles="updateFiles"
      >
        <span class="padding"> 上传文件夹</span>
      </FileUpload>
    </el-dropdown-item>
  </el-dropdown-menu>
</el-dropdown>

<style lang="scss" scoped>
.padding {
  padding: 0 20px;
}

::v-deep {
  .el-dropdown-menu__item {
    padding: 0;
  }
}
</style>

38. css属性选择器

  ·el-col[class*='el-col-1.5']表示一个css选择器,用于选择包含el-col-1.5这个类名的 html元素,并且这些html元素的class属性中必须包含el-col这个类名。

39. el-popover悬浮框位置修改

  为el-popover指定popper-class属性,添加类名即可,比如popper-class="mt20"。以下是效果:

image.png

40. background-imageurl参数的注意事项

<style lang="scss" scoped>
.bg {
  // ~ 在SCSS 中用于表示导入模块或文件的路径
  // 在Vue CLI创建的项目中,默认配置了别名@来指向src目录
  background-image: url('~@/assets/images/loginBg.png');
}
</style>

41. css动画设置animation, 实现抖音loading效果

<template>
  <div class="app-container ball-box">
    <div class="ball red"></div>
    <div class="ball blue"></div>
  </div>
</template>

<style lang="scss" scoped>
.ball-box {
  display: flex;
}
.ball {
  position: relative;
  width: 20px;
  height: 20px;
  border-radius: 50%;
}
.ball.red {
  background-color: #e94359;
  animation: redRotate linear 1s infinite;
}
.ball.blue {
  background-color: #74f0ed;
  animation: blueRotate linear 1s infinite;
}
@keyframes redRotate {
  0% {
    transform: translateX(0);
    // 红色小球在起点位置,设置比蓝色小球更高的层级
    z-index: 1;
  }
  50% {
    transform: translateX(20px);
  }
  100% {
    transform: translateX(0);
    // 红色小球在终点位置,设置比蓝色小球更低的层级
    // 红色小球从起点位置运动终点位置这一过程,会造成蓝色小球被覆盖的现象,
    // 红色小球返从终点位置回到初始位置这一过程,就会造成被蓝色小球覆盖的现象,实现两个小球在旋转的假象
    z-index: 0;
  }
}
@keyframes blueRotate {
  0% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(-20px);
  }
  100% {
    transform: translateX(0);
  }
}
</style>

image.png

42. 记一次奇妙的探索

// 重叠的box1和box2具有相同的层级,而文字未脱离正常文档流,所以会覆盖

<template>
  <div class="app-container">
    <div class="box1">我是层级1</div>
    <div class="box2">我是层级2</div>
  </div>
</template>

<script>
export default {}
</script>

<style lang="scss" scoped>
.box1,
.box2 {
  width: 200px;
  height: 200px;
}
.box1 {
  background: orange;
}
.box2 {
  background: pink;
  margin-top: -200px;
}
</style>

image.png

// box2具有更高的层级,同时设置opacity, 相当于穿透了这一个块,所以颜色会叠加
// 而box2具有更高的层级,所以box2的文字在box1文字的上方

<template>
  <div class="app-container">
    <div class="box1">我是层级1</div>
    <div class="box2">我是层级2</div>
  </div>
</template>

<script>
export default {}
</script>

<style lang="scss" scoped>
.box1,
.box2 {
  width: 200px;
  height: 200px;
}
.box1 {
  background: orange;
}
.box2 {
  background: pink;
  opacity: 0.8;
  margin-top: -200px;
}
</style>

image.png

<template>
  <div class="app-container">
    <div class="box1">我是层级1</div>
    <div class="box2">我是层级2</div>
  </div>
</template>

<script>
export default {}
</script>

<style lang="scss" scoped>
.box1,
.box2 {
  width: 200px;
  height: 200px;
}
.box1 {
  background: orange;
  opacity: 0.8;
}
.box2 {
  background: pink;
  margin-top: -200px;
}
</style>

image.png

// box1和box2的层级相当于都是1,但是由于box2覆盖了box1,所以box2层级更高

<template>
  <div class="app-container">
    <div class="box1">我是层级1</div>
    <div class="box2">我是层级2</div>
  </div>
</template>

<script>
export default {}
</script>

<style lang="scss" scoped>
.box1,
.box2 {
  width: 200px;
  height: 200px;
}
.box1 {
  background: orange;
  opacity: 0.8;
}
.box2 {
  background: pink;
  margin-top: -200px;
  opacity: 0.6;
}
</style>

image.png

<template>
  <div class="app-container">
    <div class="box1">我是层级1</div>
    <div class="box2">我是层级2</div>
  </div>
</template>

<script>
export default {}
</script>

<style lang="scss" scoped>
.box1,
.box2 {
  width: 200px;
  height: 200px;
}
.box1 {
  background: orange;
  opacity: 0.6;
}
.box2 {
  background: pink;
  margin-top: -200px;
  opacity: 0.8;
}
</style>

image.png

// 不同于普通的文档流,flex有一套自己的布局方式,box1和box2分别是两个不同的整体。
// 但只要加上opacity这个属性,就相当于这个块被穿透,因此文字和背景颜色都会叠加

<template>
  <div class="app-container">
    <div class="box1">我是层级1</div>
    <div class="box2">我是层级2</div>
  </div>
</template>

<script>
export default {}
</script>

<style lang="scss" scoped>
.app-container {
  display: flex;
}
.box1,
.box2 {
  width: 200px;
  height: 200px;
}
.box1 {
  background: orange;
}
.box2 {
  background: pink;
  margin-left: -200px;
}
</style>

image.png

  有flex布局的前提下,设置opacity属性与上述截图结果一致。设置了opacity属性的元素,具有更高的z-index层级。对于上述情况,浅猜一波浏览器的渲染机制: 浏览器的渲染机制犹如画布一样,层级越低的越先被描绘。 又因为我们能看到背景颜色上的文字信息,所以背景颜色在下层,文字信息在上层。因此,浏览器是先渲染背景颜色,再渲染文字信息。且相比于层级较高的背景颜色和文字信息,层级较低的背景颜色和文字信息先被渲染。

43.修改iframe中的dom样式(以修改tinymce-vue编辑器中的图片样式为例)

`相关资料参考:https://www.python100.com/html/5Z5J70N5L4XC.html`

imageHandler() {
  setTimeout(() => {
    `先获取iframe`
    const iframe = document.getElementsByTagName('iframe')[0]
    `再获取iframe中的dom内容`
    const iframeDoc = iframe.contentDocument || iframe.contentWindow.document
     `最后获取iframe中的图片dom`
    const images = [...iframeDoc.getElementsByTagName('img')]
    images.map((img) => (img.style.objectFit = 'contain'))
  }, 300)
}

44. 左右容器,左侧固定定位,内部超过指定高度出现滚动条

45. css盒子模型

  在css中存在两种模型:box-sizing: border-boxbox-sizing: content-box(默认)box-sizing: border-box的高度包含borderpadding和文本content的内容,而默认盒子的高度是不包括paddingborder的值的。

image.png

46. 某个dom元素下的伪元素(转换为行内块元素),可以使用vertical-align: middle,来实现伪元素和dom元素的垂直居中

47. 响应式布局

48. outline

49. 用,表示同级关系,同级中的类都需要修改为对应的样式

`修改表格高度样式`

<style lang="scss">
.statistics-unique-dialog {
  .el-table__body-wrapper,
  .is-scrolling-none {
    height: auto !important;
    max-height: 400px;
    overflow-y: auto;
  }
}
</style>

`而.a .b表示修改a类下b类的样式`

50. 在vue文件中引用scss文件(不同分辨率屏幕下的样式适配方案)

`错误的做法:在每个需要修改适配的文件下,使用媒体查询修改样式,这样的做法是导致文件错乱,不方便维护`
`正确的做法:在每一个页面的主index文件中,引入对应的scss文件,再使用媒体查询修改样式,方便统一管理和维护`

`1. 在vue文件中引用scss文件:`

`第一种方式:`
<style lang="scss" scoped>
</style>

`放在后面,可以覆盖前面同级的重名类`
<style lang="scss" scoped src="./scss/media.scss">
</style>

`第二种方式:`
<style lang="scss" scoped>
...
@import "./styles/media";
</style>

`2. 在scss文件中引用scss文件:`
@import './variables.scss';
@import './crud-quill/quill.core.css';
@import './crud-quill/quill.snow.css';
@import './crud-quill/quill.bubble.css';
@import './element-ui.scss';
@import './data-display.scss';
@import './data-card.scss';
@import './data-tabs.scss';
@import './data-icons.scss';
@import './crud.scss';

51. 富文本编辑器中的换行注意事项

<div v-if="data.content" v-showImageViewer v-html="content" class="html-content-wrapper">
</div>

export default {
  computed: {
    content({ data: { content } }) {
      `因为富文本编辑器会将空格转换为&nbsp;`
      `携带这些标记的文本, 会影响到word-wrap和white-space对于文本换行的判断`
      `所以,需要将所有空格符转换为空格`
      
      `那么为什么不使用replaceAll呢?`
      `因为replace兼容性更好`
      return content.replace(/&nbsp;/g, ' ')
    }
  }
}

`但是white-space默认值是将多个空格合并成一个空格,这样我们在富文本中连续使用的空格符,就会合并为一个`
`从而影响样式,这并不是我们希望看到的。为保留文本中原有的空格符,需要使用到white-space: pre-wrap`
`并将样式挂载到富文本解析文本中的p标签上。如果直接对html-content-wrapper使用以下样式,会产生高度,撑开p标签`

.html-content-wrapper {
  ::v-deep {
      p {
        word-wrap: break-word;
        white-space: pre-wrap;
      }
  }
}

52. 对于移动设备,以网页800px以下的媒体查询布局方式,访问网站

public/index.html中:

<meta name="viewport" content="width=800,user-scalable=yes">

53. 行内块元素的子级,会受到父级flex布局的影响,从而具备flex的特性

<template>
  <div class="flex-wrap">
    <span v-for="(item, index) in 4" :key="index" class="inline-block w50">
        我是子项{{ index }}
    </span>
  </div>
</template>

<style lang="scss" scoped>
.flex-wrap {
  display: flex;
  flex-wrap: wrap;
}

.w50 {
  width: 50%;
  height: 100px;
  line-height: 100px;
  text-align: center;
}
</style>
image.png

54. 方形图片布局

`使用el-row进行响应式布局,四个占一行`

<el-row class="flex-wrap" :gutter="20">
  <el-col class="flex-item-wrapper" v-for="(item, index) in option.data" :key="index" :span="6">
    <div class="image-wrapper">
      <el-image fit="contain" class="image" :src="item.path" @click="linkTo(item.id)"></el-image>
    </div>
    <div class="name text-cut">{{ $getValueOfLanguage(item, 'name') }}</div>
    <div class="price">{{ item.price }}</div>
  </el-col>
</el-row>


`为了让子元素不撑开父元素,使父元素高度为0的同时.使用padding-top: 100%,将父元素的高度设置为与子元素宽度相同`
.image-wrapper {
    position: relative;
    `继承el-image25%的宽度,父元素具有25%宽度的高度`
    padding-top: 100%;
    margin-bottom: 15px;
    cursor: pointer;
    .image {
      position: absolute;
      top: 0;
      left: 0;
      `子元素具有25%的宽度`
      width: 100%;
      `保持父元素的高度,即25%的宽度`
      `此时子元素的宽 = 子元素的高 = 父元素的高,因此成为了方形。`
      `也不会因响应式宽度变化和图片contain布局,导致图片高度大小不一,因为高度都被固定成了25宽度`
      height: 100%;
    }
}

image.png

55. 部分css选择器汇总

`abc共有的样式:`

.a, .b, .c {

}


`a下的b下的c的样式:`

.a .b .c {

}

`样式权重不够时,连写多个相同类名,加强权重`

.a.a.a {

}

56. vue中子组件的最外层样式,也会合并到父组件中。在父组件中,使用子组件的最外层不用deep, 使用子组件中的其他样式需要deep

57. el-row标签可以指定type = 'flex',实现flex布局

58. 图片加载性能优化——失败时的回退机制(使用另外一张图片, 图片加载成功前,使用样式提前占位)

`compatibleImg.vue`

`图片未成功加载时,高度默认为50vh占位`
`图片加载成功后,高度为图片的高度`

<template>
  <el-image v-bind="all$Attrs" v-on="all$Listeners" :src="url" @load="onLoad">
    <template #error>
      <el-image v-bind="all$Attrs" v-on="all$Listeners" :src="backUrl" @load="onLoad"> </el-image>
    </template>
  </el-image>
</template>

<script>
import { merge } from 'lodash'

`定义默认配置项`
const DEFAULT_OPTION = {
  fit: 'cover',
  class: 'banner'
}

export default {
  props: {
    `首选特定格式的图片,比如webp格式的小体积图片`
    url: String,
    
    `首选图片在其他浏览器上不兼容时的回退机制,一般是png或者jpeg格式的图片`
    backUrl: String,
    
    `外部传来的自定义样式,交给父组件定义并处理。比如可以控制图片成功加载前,用于提前占位的高度`
    customClass: String
  },

  data() {
    return {
      loaded: false
    }
  },

  computed: {
    all$Attrs({ $attrs, loaded }) {
      return merge(
        {},
        DEFAULT_OPTION,
        { class: [DEFAULT_OPTION.class, loaded && 'loaded-banner', this.customClass] },
        $attrs
      )
    },

    all$Listeners({ $listeners }) {
      return merge({}, { load: this.onLoad }, $listeners)
    }
  },

  methods: {
    async onLoad() {
      this.loaded = true
    }
  }
}
</script>

<style lang="scss" scoped>
.banner {
  `图片继承父级100%的宽度`
  width: 100%;
  `消除幽灵节点的影响`
  padding: 0;
  `经验值,加载中默认指定50vh的高度`
  height: 50vh;
}

.loaded-banner {
  `加载中图片高度根据自身高度自适应`
  `但是如果为外层图片指定了高度,这个高度就不会是响应式的效果,而是给定的图片高度`
  `因此,如果想使用这个组件,不要一开始就在外层给图片固定高度`
  height: auto;
}
</style>
`使用:`

<compatibleImg :url="url" :backUrl="backUrl" />

data() {
  return {
    url: require('./pic/banner.webp'),
    backUrl: require('./pic/banner.png') 
  }
}

效果:

4M@UX`F7PKFZA147B`EQEZQ.png

59. 三栏布局--如何实现主体内容先加载

`浏览器会按照HTML文件的顺序下载和解析内容`
`flex布局中的order属性,用于定义项目的排列顺序,数值越小,排列越靠前。`

<div class="page">
    <div class="content">中栏内容</div>
    <div class="left">左栏内容</div>
    <div class="right">右栏内容</div>
</div>

.page {
  display: flex;
}

.content {
  order: 1;
  flex: 1;
}

.left {
  order: 0;
  width: 200px;
}

.right {
  order: 2;
  width: 200px;
}

60. template:可以看作为一个不在dom中显示的div标签,用作占位符

61. 响应式布局实践方案

  • 需求:

    需要在原有项目的基础上,适配在各种屏幕上(包括800px到2560px宽度)的样式。

  • 解决方案:

    1. 假定UI提供的稿件宽度是1920px,前端需要对UI提供的稿件进行一比一还原;
    2. 我们可以建立pxvw之间的关系, 把1920px视为100vw,那么1vw = 19.2px。 如果设计稿上某个元素的宽度为192px, 那么将它换算得到的结果将会是192px / 19.2px * 1vw = 10vw。我们在布局时,严格按照设计稿提供的元素大小,只不过需要将它转换为vw。而对于这一过程,我们可以借助下文的方法实现;
    3. 不同屏幕下的元素显示势必不会那么完美,但是我们可以通过媒体查询,在不同分辨率的屏幕下进行适配,这样就可以解决问题。
  • 方法封装:

// topicVariables.scss

//1vw = 1920 / 100 ;
$proportion: 19.2;

// 自定义scss函数, 作用是去掉传入变量的单位
// 之所以要去掉单位,是为了将传入的px转换为vw

@function stripUnits($value) {
  // 对带有单位的变量进行特殊处理,返回去掉单位后的结果
  // 对于scss来说, 90px和90都是number
  @if type-of($value) == 'number' and not unitless($value) {
    // 90px / 1得到的结果是90px, 90px / 1px得到的结果是90
    // 这也是这里为什么要用($value * 0 + 1),而不是直接写1的原因
    @return $value / ($value * 0 + 1);
  }
  @return $value;
}

// 自定义scss函数,提供三个参数
// 第一个参数是设计稿提供的元素大小,传入会自动转换为vw单位,达到自适应的效果
// 第二个参数是用来约束这个元素的大小最大不能超过第一个参数和第二个参数的最大值
// 第三个参数是用来约束这个元素的大小最小不能小于第一个参数和第三个参数的最小值
// 应用场景是比如1920px下标题的字体是48px,当到800px时,标题字体会小一大半,比24px还要小,
// 我们不希望它这么小,于是可以给他设置一个最小值,比如最小不能小于32px,不然起不到突出的作用

@function auto($raw, $max:null, $min:null) {
  // 如果$raw有单位,将$raw去掉单位
  $raw: stripUnits($raw);
  
  // 将$raw转换为vw单位
  $str: #{$raw / $proportion}vw;
  
  @if $max {
    $str: min(#{$str}, #{$max});
  }
  
  @if $min {
    $str: max(#{$str}, #{$min});
  }
  
  @return $str;
}

// 自定义scss函数,auto方法的二次封装, 提供两个参数
// 第一个参数用于转换传入的像素档位,即默认都是响应式的
// 第二个参数用于用于设置这个元素的最小值

@function autoMax($raw, $min:null) {
  @return auto($raw, $raw, $min)
}

$text-mini-1: 16px;
$text-small-1: 18px;
$text-sm-md-1: 20px;
$text-medium-1: 24px;
$text-large-1: 36px;
$text-title-1: 48px;

$auto-text-mini-1: autoMax($text-mini-1, 14px);
$auto-text-small-1: autoMax($text-small-1, 16px);
$auto-text-sm-md-1: autoMax($text-sm-md-1, 16px);
$auto-text-medium-1: autoMax($text-medium-1, 16px);
$auto-text-large-1: autoMax($text-large-1, 20px);
$auto-text-title-1: autoMax($text-title-1, 32px);
`vue.config.js中全局挂载:`

css: {
    loaderOptions: {
      sass: {
        additionalData: `
            @import "~@/styles/topicVariables.scss";
        `
      }
    }
}
  • 方法使用:
.container {
  // 如果1920以上的屏幕需要保持和1920一样的布局大小,就这么写,默认他最大高度就是1920屏幕下提供的值
  // 屏幕就算再宽,最大高度也固定在360px
  // 如果需要自适应,就使用auto(360px),它会根据屏幕大小进行缩放
  height: autoMax(360px); 
}
image.png

62. 带有渐变色的背景

方法一:
background: url('./images/howpic0.png'), linear-gradient(180deg, #8acfe6 0%, #ffffff 100%);

方法二(background-image支持多个背景叠加):
background-image: url('./images/howpic0.png'), linear-gradient(180deg, #8acfe6 0%, #ffffff 100%);

62. 修改svg颜色

_CTHF6$Q%U~{)AM(V}G47U9.png

63. 使用属性选择器为含有小数点的类名设置样式

[class*='el-col-4.8']是属性选择器, 它选择所有具有包含子串el-col-4.8的class属性的元素。

[class*='el-col-4.8'] { 
  width: 20%; 
}

64.html中的video标签可以原生支持MP4格式视频播放,但是对视频编码有要求,大部分的浏览器只能够原生支持avc(h.264)

65. 一屏移动端100vh陷阱: 在不同浏览器上,可能会存在滚动条

// 解决方法:

const appHeight = () => {
    const doc = document.documentElement
    doc.style.setProperty('--app-height', `${window.innerHeight}px`)
}
window.addEventListener('resize', appHeight)
appHeight()
:root {
   --app-height: 100%;
}

.content{
    height: calc(var(--app-height) - 100px);
}

66. 巧用meta标签处理跨域问题

67. 巧用fliter属性为图片中的物体描边

 filter: drop-shadow(0 0 5px red);

image.png

68. 鼠标悬浮显示图片的两种方法

// 第一种方式:
隐藏:
opacity: 0;

显示:
opacity: 1;

// 第二种方式:
隐藏:
display: none;

显示:
display: inline-block;

// 鼠标悬浮显示懒加载的el-image图片时,需要使用第一种方式,使用第二种方式无法触发图片的load事件
image.png image.png image.png

69. vue中也存在鼠标移入事件@mouseenter

70. 需要频繁为图片切换src路径时,不适合使用el-image。 因为会存在图片loading的闪动问题,而使用原生img标签则不会。

71. 背景缩放时,保持背景的横纵比

第一种:
background: url('./pic/background.png') no-repeat center;
background-color: #065349;
background-size: contain;

第二种:
background: url('./image/1-background-2.jpg') no-repeat center / 100% 100%;
image.png

结语

  就这样吧~ 以上内容是我的CSS世界。最近比较忙,后续如果有空会学习下react