不再为CSS感到诡异,来了解CSS和HTML是如何配合设计出页面的

258 阅读6分钟

前言

大家好,我是抹茶,一个已经工作了五年+的前端。 在日常的工作当中,会听到一些声音——“css很难,没有逻辑性”。如果只是孤立的看每一个规则,确实是很分散,但如果结合HTML布局规则去看,我们会能从中发现一些设计的规律。

以每个DOM的大小及位置是如何确定的为主线,我们来研究这其中是哪些规则、样式在起作用。

1. html的布局规则

首先,html的布局规则遵循“从左到右,从上到下”。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .up {
        background-color: skyblue;
        height: 100px;
      }
      .down {
        background-color:pink;
        height: 100px;
      }
    </style>
  </head>
  <body>
    <div class="up">
      <span>我是第一句话</span>
      <span>我是第二句话</span>
    </div>
    <div class="down"></div>
  </body>
</html>

image.png

如果所示,浏览器是先绘制了第一个.up的dom,然后再绘制.down的dom,这就是从上到下。 先绘制了 <span>我是第一句话</span>,再绘制<span>我是第二句话</span>,这就是从左到右

2.块级元素和内联元素的特性与转换

html标签是会分为块级元素和内联元素。 块状元素的宽度会默认占完整个容器,像水流一样。

image.png

如图,块状元素默认会如同水流一样占满整个容器,所以又叫文档流,相当于这些html的标签会流动铺开,渲染好整个页面。

块级元素好比书架上一个个的盒子,负责搭建框架,内联元素好比书架里的一本本书,负责内容填充。

image.png

常见的块级元素有: div、setion、header、nav、footer、p
常见的内联标签有: span

内联元素的宽高默认是由内容的内容撑开的,通过style设置宽高是无效的。

<body>
    <div class="up">
      <span style="margin-right: 40px;width:500px;height:500px">我是第一句话</span>
      <span>我是第二句话</span>
    </div>
    <div class="down"></div>
  </body>

如图所示,给span设置宽高是无效的,因为它默认display:inline,margin左右是生效的。因为内容是可以隔开的。

image.png

如果对span设置display:block,它就变成一个块,块是可以设置宽高的。

image.png

同样的,对块级元素设置display:inline,它就失去了扩张性,大小是由内容撑开。

image.png

3.盒模型

image.png

如图,一个DOM元素,从里到外是由content-box、padding-box、border-box、margin-box构成的。每个盒子是有4个面的,所以可以分别设置四个方位的样式。

一般来说,整个DOM占据的宽高是content-box + padding-box + border-box 的总和(默认box-sizing:content-box),我们设置的width是作用在content-box上。如图DOM在整个文档流中占据的宽高是244 * 144.

image.png

如果我们设置box-sizing:border-box那就把width设置的作用范围扩大到border-box,整个DOM占据的宽度就是设置的200px,content-box的宽度也就自动缩小到200 - border部分- padding部分。

image.png

4.内容盒子的高度

默认情况下,内容盒子(inline元素)的高度是由文字的line-height撑起来的。 一般情况的时刻,可以内容盒子的高是22.5px。

image.png

在设置line-height之后,文字往下掉了。

image.png

添加设置display:inline-block,我们能更直观看到效果。

image.png

当我们把font-size设置成一个很大的值的时候,元素高度变成了320px;

image.png 这320px是怎么来的呢?首先font-size设置是80px,文字换行变成两行,line-height设置为160px, 160 * 2 = 320px

如果没有换行,就还是160px.

image.png

把font-size设置成一个比行高还要大的值,可以发现高度还是160px,所以可以说一般情况下line-height决定了内联元素的高度。

image.png

5.DOM的位置

css中有positon的属性,默认是static。也就是按顺序从上到下,从左到右排列。如果不是static,则一般有下面的规则。

  • relative 相对于原来的位置进行定位,可以设置left、right、top、bottom
  • absolute 会相对第一个非static的父级元素定位,可以设置left、right、top、bottom
  • fixed 默认是相对视窗进行定位,当元素祖先的 transformperspectivefilter 或 backdrop-filter 属性非 none 时,容器由视口改为该祖先。
  • sticky 基于用户的滚动位置来定位,与left、right、top、bottom组合使用。当距离满足方位设置值时,表现同fixed,被黏住了一样。

6.DOM的间隔

可以用position结合left、right、top、bottom来创建间隔,一般用的是margin。

6.1 margin无效的情况

inline元素的margin-top和margin-bottom是无效的,因为放置的东西不能悬空。但是margin-left和margin-right是有效的。也就是说inline作为内容,只可以设置它距离左右的间隔,如下图

image.png

6.2 margin合并的情况

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      body {
        margin: 0;
      }
      .up {
       
        background-color: skyblue;
        height: 100px;
        margin-bottom: 40px;
      }
      .down{
        margin-top:20px;
        background-color: brown;
        height: 200px;
      }

      .content{
        margin-left:20px;
        margin-right:20px;
        margin-top:20px;
        margin-bottom: 20px;
      }
    </style>
  </head>
  <body>
    <div class="up">
      <span class="content">hello world</span>
    </div>

    <div class="down">
      <span class="content">hello world</span>
    </div>
  </body>
</html>

image.png

我们给上面盒子设置了margin-bottom:40px,给下方盒子设置了margin-top:20px,浏览器实际上只间隔了40px,也就是合并了,取间隔的最大值。

7.层级堆叠

我们有时候会希望A叠加到B上面,这个时候一个图层就不够了,需要A图层叠加到B图层上面。从Layers面板就可以看到有三个图层。

image.png
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      body {
        margin: 0;
      }
      .up {
        position: relative;
        background-color: skyblue;
        height: 200px;
        margin-bottom: 40px;
      }

      .B {
        top: 20px;
        width: 100px;
        height: 100px;
        background-color: aqua;
        position: absolute;
      }

      .C {
        z-index: 1;
        top: 50px;
        width: 100px;
        height: 100px;
        background-color: yellow;
        position: absolute;
      }
    </style>
  </head>
  <body>
    <div class="up">
      A
      <div class="C">c</div>

      <div class="B">B</div>
    </div>
  </body>
</html>

看body部分的代码,B在C后面,正常来说是后渲染的会覆盖前面的,但因为我们对C设置了z-index:1,C的层级比B高,我们就看到C覆盖在B上面了。

image.png

总结

这篇文章从HTML的布局规则,结合块级元素和内联元素的特性,把DOM元素的位置、大小、间隔、层级涉及的相关属性做了探究,以DOM的排布枝干为主线,穿插容易忽略的细节讲解,让大家可以知道DOM的位置是怎么确定、大小是如何收到关键属性的影响的。这些是作为布局的主干属性,其他的css属性属于更好描绘,希望通过这篇文章不再迷茫css如何影响到DOM的大小与布局。