恋の歌的logo
Auto
归档 标签

CSS之双飞翼布局和圣杯布局

发表于2020-09-23 15:01
更新于2023-02-13 18:28
分类于编程
总字数1.6K
阅读时长 ≈6 分钟

CSS之双飞翼布局和圣杯布局。

这两种布局都是左右固定,中间自适应,也就是占满。

并且兼容性很好,中间部分优先渲染。

圣杯布局 🔗

使用了浮动,负边距以及相对定位

html

html
<body>
  <header>header</header>
  <main>
    <section id="center" class="col">center</section>
    <section id="left" class="col">left</section>
    <section id="right" class="col">right</section>
  </main>
  <footer>footer</footer>
</body>

css

css
header,
footer {
  padding: 20px 0;
  text-align: center;
  background-color: #9d9d9d;
}

main {
  padding-left: 200px;
  padding-right: 150px;
}

.col {
  float: left;
  height: 200px;
}

#left {
  width: 200px;
  background-color: pink;
  margin-left: -100%;
  position: relative;
  right: 200px;
}

#right {
  width: 150px;
  background-color: lightcoral;
  margin-left: -150px;
  position: relative;
  right: -150px;
}

#center {
  width: 100%;
  background-color: lightskyblue;
}

footer {
  clear: both;
}

效果图:

双飞翼布局 🔗

html

html
<body>
  <header>header</header>
  <main>
    <section class="col" id="center">
      <section id="inside-center">
        I'm Tong tong ,I'm 12 years old .There are three people in my family
        ----my father ,my mother and I .In summer, I like swimming. In fall, I
        like flying kites . In winter , I like making a snowman . In spring , I
        like planting trees.I like singing and dancing . Can you tell me , what
        about you.
      </section>
    </section>
    <section id="left" class="col">left</section>
    <section id="right" class="col">right</section>
  </main>
  <footer>footer</footer>
</body>

css

css
header,
footer {
  text-align: center;
  padding: 20px 0;
  background-color: #9d9d9d;
}

.col {
  float: left;
  height: 200px;
}

#left {
  width: 200px;
  background-color: pink;
  margin-left: -100%;
}

#right {
  width: 150px;
  background-color: lightcoral;
  margin-left: -150px;
}

#center {
  width: 100%;
  background-color: lightskyblue;
}

#inside-center {
  margin-left: 200px;
  margin-right: 150px;
}

footer {
  clear: both;
}

效果图:

区别 🔗

从上面可以看出,圣杯和双飞翼的布局的主要区别在:

如何腾出中间栏左右的位置来来适应左右栏的宽度?

圣杯布局中,使用了相对定位和左右padding来实现。

我们对整个包裹中间的main使用了padding,使得这个盒子的content-box的宽度变小。

在里面的center列使用了100%宽度来占满整行,使得另外两行都被放到了下一行的位置。

上图可以看出左右两边的留白就是给main设定padding的效果。

而由于我们是先写center列再写left列和right列的,所以100%宽度的center占满第一行

左右定长的列left列和right列便依次放在第二行

如果现在把先写left列再写center列和right列的话,就会是下面这种情况:

但是即使这样我们也可以实现圣杯布局。

怎么做呢?其实想法是差不多的。

第一步,我们先把center行拉到第一行来,使用左负边距,值为负的左列的宽度。

这时候我们发现left列不见了,其实不然,他只是在center列的下面而已。

接下来,我们要把right列也给拉到第一行来,使用做负边距,值为负的右列的宽度。

现在我们已经完成了90%的工作,剩下的就是把左右两列拉到padding出来的位置上。

使用相对定位,定位左右两列盒子:

完成效果如下(动图好像录制不了太长,晕…):

ok回到前面,我们为什么要先写center列再写left列和right列呢?

答案就是我们希望中间的列先渲染出来。

渲染树的渲染(DOM树,也就是HTML的节点树 + CSSOM 树,css样式形成的树)类似DFS深度优先遍历。

我们可以用debugger断点,来强制阻塞当前的渲染。

html
<div>
  <div>
    <p>hello before</p>
  </div>
  <script>
    debugger;
  </script>
  <div>
    <p>hello after</p>
  </div>
</div>

从图来看确实是这么回事,解析渲染树

但是遇到了内联的 js 代码,停下来执行了 js 代码,执行完毕继续解析

这里可以看下面这篇文章,我觉得相当不错

浏览器是如何解析 html 的?

ok,写完了圣杯布局,来看看双飞翼是如何实现的

对于如何腾出中间栏左右的位置来来适应左右栏的宽度?

双飞翼布局使用了在center列增加一个内部的盒子。

使用margin-leftmargin-right正数值来实现。

在三列只设定浮动的情况下,会是下面这个样子。

到此为止,看出和圣杯布局的差别了没有,没错,就是少了main盒子的padding而已。

接下来的事情和圣杯布局是一样的,我们要把left列拉到第一行,放到最左侧。

right列拉到第一行,放到最右侧,使用负边距来实现。

ok 现在我们已经把三个列都放到一行了,但有个问题没有解决,就是center列的左右被挡住了。

没错,双飞翼解决的办法就是在center列中增加一个盒子。

指定这个在内部盒子的margin-leftmargin-right来腾出左右的地方。

ok,这两种布局基本上就是这样子了,我还是喜欢圣杯布局的,毕竟少一个内部的盒子嘛~

最后 🔗

其实这两种布局都基于负边距margin和相对定位来实现

负边距margin 🔗

会使得盒子重叠,我的理解比较的简单,正的边距表示我应该离你“远一点”。

那么负边距意味着我应该离你“近一点”,即使我和你会重叠。

注意,负边距是会改变盒子的真正位置的,这和相对定位不同。

比如下面的gif,可能可以帮你理解负的margin

html
<div id="box1" style="background-color: #4b8cff">1</div>
<div id="box2" style="background-color: #9d9d9d">2</div>
<div id="box3" style="background-color: #db7093">3</div>
css
body {
  font-size: 0;
}
div {
  display: inline-block;
  font-size: 14px;
  width: 200px;
  height: 200px;
}
javascript
// 简单的动画,记得写在body最后的一个script标签中
let dir = 1;
let step = 0;
setInterval(() => {
  document.getElementById("box2").style.setProperty("margin-left", step + "px");
  if (step === 200) {
    dir = -1;
  } else if (step === -200) {
    dir = 1;
  }
  step += dir;
}, 16);

效果图:

可以看出,我们控制的盒子2的样式,但是盒子3和盒子2一起运动。

也就是说盒子2在文档流的位置是不断变化的。

相对定位position: relative 🔗

相对定位可以让盒子基于文档流的位置以自身位置进行偏移。

但是文档流的位置是不会改变的(也就是元素还是会占据没相对定位前的位置,下面的动图可以看出)。

还是用负边距margin的例子,改下css

css
body {
  font-size: 0;
}

div {
  display: inline-block;
  font-size: 14px;
  width: 200px;
  height: 200px;
  /* 设置为相对定位 */
  position: relative;
}
javascript
let dir = 1;
let step = 0;
setInterval(() => {
  // 使用 相对定位的 left 来控制
  document.getElementById("box2").style.setProperty("left", step + "px");
  if (step === 200) {
    dir = -1;
  } else if (step === -200) {
    dir = 1;
  }
  step += dir;
}, 16);

效果图:

不管移动到哪里,原来的位置就是盒子2在文档流的位置,相对定位的盒子移动不会影响到其他的盒子。

#CSS
#布局
哦呐该,如果没有评论的话,瓦达西...