那些年,奇妙的圣杯与双飞翼,还有负边距

字节领航家
• 阅读 6719

[TOC]

没错,题目就是模仿《那些年,我们一起清除过的浮动》而来的。

奇妙的圣杯与双飞翼

相信很多人和我在学习前端差不多的时候就听说过了圣杯布局与双飞翼布局。关于取名无非是觉得长得像圣杯,或者是长得像小鸟。至于其中的区别也只有一小点,其中主要的思想可谓是基本一致!

这两个布局要实现的样式都是下面的这种形式:

那些年,奇妙的圣杯与双飞翼,还有负边距

也就是中间的那一部分,长得像圣杯或者是飞翔的小鸟,left 和 right 宽度已知,中间自适应填充。一般情况下,如果这样写代码,显然是很好实现布局的。

<div class="head">head</div>
    <div class="content">
        <div class="left">left</div>
        <div class="main">main</div>
        <div class="right">right</div>
    </div>
 <div class="foot">foot</div>

但是相应的按照 DOM 的加载顺序,content 部分依次会加载 left、main、right。这对于有洁癖的人可能是无法忍受的,甚至是觉得不符合常理。

正常情况下,我们希望先加载的是主要部分,然后再开始加载 left 和 right 两个相对来说不是很重要的东西。所以 HTML 代码应该这样写:

<div class="head">head</div>
    <div class="content">
        <div class="main">main</div>
        <div class="left">left</div>
        <div class="right">right</div>
    </div>
<div class="foot">foot</div>

另外一方面来说,我们倡导语义化的 HTML,也就是说在编写 HTML 的时候不应该受制于 CSS 的干扰,所以这样的写法来达到上面的布局也应该是必要的。

那么如果这样写应该如何去写 CSS 样式呢?

首先我们的想法可能是先搭建起 head content 和 foot,content 里面的东西全部用左浮动解决,对 content 要清除浮动让他撑起高度。代码如下:

* {
    margin: 0;
    padding: 0;
}
.cleanfix {
    clear: both;
}
.cleanfix:after {
    content: '.';
    clear: both;
    display: block;
    visibility: hidden;
    height: 0;
    zoom: 1;
}
.head, .foot {
    width: 100%;
    height: 80px;
}
.head {
    background-color: #4eb5f7;
}
.foot {
    background-color: #999999;
}
.left, .right, .main {
    float: left;
}
.left {
    width: 40px;
    height: 60px;
    background-color: #B9E078;
}
.right {
    width: 60px;
    height: 80px;
    background-color: #FF9900;
}
.main {
    background-color: crimson;
}

这样的话就能实现下面的布局:

那些年,奇妙的圣杯与双飞翼,还有负边距

我们要的目的是 main 布局自适应,这样的话我们给 main 100% 的宽度:

.main {
  100%;
}

这样的话布局就会变成这样:

那些年,奇妙的圣杯与双飞翼,还有负边距

接下来,我们想要 left 跑上去,这个时候就可以使用奇妙的负边距了。

main, left, right 我们都可以看做是在一个浮动流中,依次的顺序也是 main left right。目前是因为 main 占了100% 从而导致 left 与 right 不能和 main 浮在同一行了,这个时候我们可以利用负边距来让 left 向前移动 (即 margin-left 为正的时候就是和左边的盒子的外边距,那么为负的时候就是像前移动了)。加上下面的特技

.left {
    margin-left: 100%;
}

那么移动多少呢?为了让 left 跑到最左边,那么就像上面的一样移动到 -100% ,也就是向左移动的最大值了。这样,会得到下面的布局:

那些年,奇妙的圣杯与双飞翼,还有负边距

我们看到 left 移动到最左边了,那 right 是不是也可以模仿 left 一起移动呢?移动多少?right 只需要向前移动right的宽度个距离,即 60px

.right {
    margin-left: -60px;
}

得到下面的结果

那些年,奇妙的圣杯与双飞翼,还有负边距

和我们想象中的一样, right 也移动上去了,并且跑到了我们想要的位置。

但是稍微细心点就能发现上面的结果还是存在问题的,红色中间部分的 main 跑到哪里去了?

打开开发者工具审查元素就能看见好像是 left 和 right 覆盖到上面去了。

那些年,奇妙的圣杯与双飞翼,还有负边距

那么如何去使得 main 部分往里面收收呢?这也就是圣马布局与双飞翼布局根本区别了

圣杯布局

圣杯布局的思想就是给包裹着三个元素的 content 加一个 padding, 让 padding-left 和 padding-right 的数值是 left 和 right 的宽度,然后利用相对定位把他们再移动在两旁。

首先,给 content padding

.content {
    padding: 0 60px 0 40px;
}

那些年,奇妙的圣杯与双飞翼,还有负边距

然后利用相对定位移动 left 和 right

.left {
    position: relative;
    left: -40px;
}
.right {
    position: relative;
    right: -60px;
}

这样也就完美的解决了问题:

那些年,奇妙的圣杯与双飞翼,还有负边距

最后 CSS 的所有样式是这样的:

* {
    margin: 0;
    padding: 0;
}
.cleanfix {
    clear: both;
}
.cleanfix:after {
    content: '.';
    clear: both;
    display: block;
    visibility: hidden;
    height: 0;
    zoom: 1;
}
.head, .foot {
    width: 100%;
    height: 80px;
}
.head {
    background-color: #4eb5f7;
}
.foot {
    background-color: #999999;
}

.left, .right, .main {
    float: left;
}
.left {
    width: 40px;
    height: 60px;
    background-color: #B9E078;
    margin-left: -100%;
}
.right {
    width: 60px;
    height: 80px;
    background-color: #FF9900;
    margin-left: -60px;
}
.main {
    background-color: crimson;
    width: 100%;
}
.content {
    padding: 0 60px 0 40px;
}

.left {
    position: relative;
    left: -40px;
}
.right {
    position: relative;
    right: -60px;
}

HTML 是这样的:

<div class="head">head</div>
    <div class="content cleanfix">
        <div class="main">main</div>
        <div class="left">left</div>
        <div class="right">right</div>
    </div>
<div class="foot">foot</div>

双飞翼布局

延续到上面的情况,圣马布局是这样做的

圣马布局的思想就是给包裹着三个元素的 content 加一个 padding, 让 padding-left 和 padding-right 的数值是 left 和 right 的宽度,然后利用相对定位把他们再移动在两旁。

而双飞翼布局是在 main 里面再添加一个 div, 然后对这个 div 进行 margin-left 和 margin-right. 即

<div class="head">head</div>
    <div class="content cleanfix">
        <div class="main">
            <div class="wrap">main</div>
        </div>
        <div class="left">left</div>
        <div class="right">right</div>
    </div>
<div class="foot">foot</div>

CSS 部分对 wrap 进行处理:

.wrap {
    background-color: darkmagenta;
    margin-left: 40px;
    margin-right: 60px;
}

那些年,奇妙的圣杯与双飞翼,还有负边距

最后我们的CSS代码是这样的:

* {
    margin: 0;
    padding: 0;
}
.cleanfix {
    clear: both;
}
.cleanfix:after {
    content: '.';
    clear: both;
    display: block;
    visibility: hidden;
    height: 0;
    zoom: 1;
}
.head, .foot {
    width: 100%;
    height: 80px;
}
.head {
    background-color: #4eb5f7;
}
.foot {
    background-color: #999999;
}

.left, .right, .main {
    float: left;
}
.left {
    width: 40px;
    height: 60px;
    background-color: #B9E078;
    margin-left: -100%;
}
.right {
    width: 60px;
    height: 80px;
    background-color: #FF9900;
    margin-left: -60px;
}
.main {
    background-color: crimson;
    width: 100%;
}

.wrap {
    background-color: darkmagenta;
    margin-left: 40px;
    margin-right: 60px;
}

总结

总结一下,圣马布局和双飞翼的流程大体上是这样的

  • 搭建 head content foot, content 内部的三个元素全部左浮动,然后清除浮动防止影响 foot

  • 给 main 100% 的宽度让他占满一行

  • 给 left -100% 的margin-left 让他移动到最左边,给 right 和他宽度一样的负 margin 让他移动到最右边

  • 针对移动后 main 的两边会被 left 和 right 重合覆盖掉做出不同的改变,这儿也就是两个布局的本质区别

    • 圣杯布局会给 content 内边距,左右分别为 left 和 right的宽度,然后再利用相对定位移动 left 和 right

    • 双飞翼布局会在 main 里面再加一层 wrap ,然后把内容都写在 wrap 里面,正对 wrap 设置他的 margin, 左右外边距和 left 与 right 一样

奇妙的负边距

相信在上面的圣马布局与双飞翼布局中已经见识到了负边距的奇妙之处了,这就是他的第一奇妙之处

浮动元素 VS 负边距

整个浮动可以看是有一个浮动流的存在,利用负边距可以让他在这个流中移动,并且会叠加到相应元素的上面

普通文档流 VS 负边距

普通元素的位置是相对于文档流而发生变化的。负边距也会使元素在文档流中发生位移。不同于相对定位的是,这些元素移动之后不会占据原来的空间。他往前移动之后,文档流也会跟着移动

元素宽度 VS 负边距

负边距可以增加元素的宽度,对于没有 width 的元素,负边距可以加宽他们。

这样就能够很好的利用负边距实现 一寸照片排列 的那种难题了。对于这种问题,比较麻烦的办法是浮动之后 margin-right, 然后对每一行的最后一个元素设置 margin-right: 0。这样就存在一个如何给最后一个元素设定这个margin-right的问题了。

利用负边距,我们可以加大子元素的margin, 然后浮动里面所有的元素,等他们都浮动起来的时候利用 overflow: hidden消除最右边的边距。

绝对定位 VS 负边距

绝对定位就是相对于父亲系元素的最近的一个定位元素的边界来决定的,这个边界也就是margin。

如果是负边距的话就能机智的实现元素垂直水平居中了

.con {
    width: 100px;
    height: 100px;
    position: absolute;
    top: 50%;
    left: 50%
    margin-left: -50px;
    margin-top: -50px;
}

参考文章

CSS布局奇淫巧计之-强大的负边距

CSS布局中圣杯布局与双飞翼布局的实现思路差异在哪?-知乎


博客原文地址

https://github.com/rccoder/blog/issues/6

欢迎 startwatch

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Stella981 Stella981
4年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这