CSS三栏布局的经典实现方法

三栏是CSS布局中常见的一种布局模式,顾名思义,就是将网页内容以三列的形式呈现。通常,三栏布局中的左栏和右栏是固定宽度的,中栏随着窗口宽度的变化而变化。本文探讨栏三栏的基本实现思路和经典方法,对其中涉及到的知识点进行梳理。

目的:实现一个左栏和右栏宽300px,中间栏宽度自适应的三栏布局

三栏布局示意图.png

基本实现思路

首先,常规思路,我们写出3个div的HTML和CSS,分别是leftColumn(左栏)、middleColumn(中栏)和rightColumn(右栏)。

HTML:

<body>    
    <div id="leftDiv">左栏</div>
    <div id="middleDiv">中栏</div>
    <div id="rightDiv">右栏</div>
</body>

CSS:

#leftDiv {
    height: 300px;  /*高度设为300像素,下同*/
    background-color: rgb(60,139,176);  /*设置背景颜色*/
}

#middleDiv {
    height: 300px;
    background-color: rgb(225,236,214);
}

#rightDiv {
    height: 300px;
    background-color: rgb(122,122,122);
}

此时,得到的网页如下图所示:


示意图.png

这是因为div的特性:默认宽度最大化(页面的100%),默认高度最小化(根据内容自适应)。

上面的CSS中,只指定栏高度height:300px,未指定宽度,所以每个div都以宽度width:100%填满所在行。

注意:此时若尝试指定每个div的宽度,例如给每个div的CSS添加语句:

width: 100px;

得到的页面如下图左图,而非右图。

示意图.png

这是因为div属于块级(block)元素,默认情况下,块级元素总是会另起一行。

为了使块级元素能位于同一行,最简单的方法是使用float属性。我们对每个div的CSS新增语句:

#leftDiv,#middleDiv,#rightDiv {
    float: left;  /*向左浮动*/
    height: 300px;  
}

使其向左浮动,得到的效果如下图所示:

示意图.png

可以看到,对CSS设置float:left属性后,三栏位于了同一行,宽度为其内容的适应宽度。此时,我们将左栏和右栏宽度设置为300px:

#leftDiv,#rightDiv {
    width: 300px;  /*设置宽度为300像素*/
    ... 
}
#middleDiv {
    ...
}

得到的效果如下图所示:

示意图.png

此时,中栏的宽度仍为其内容的适应宽度,我们为middleDiv添加如下语句:

width: calc(100% - 600px);  /*设置middleDiv宽度*/

calc()的作用为动态计算长度值,允许各种单位混合运算,运算符前后需有空格。

于是我们得到了最终效果。左栏和右栏各300px宽,中栏根据浏览器窗口大小进行动态调整。但需要注意的是,当浏览器窗口宽度小于600px时,中栏的宽度将小于0。为此,我们可以为浏览其设置最小调整宽度,避免页面混乱:

body {
    min-width: 700px;
}

至此,一个三栏布局就完成了。这种实现思路比较符合人的思维定势,但也存在一定的缺陷:浏览器加载和渲染页面遵循从上到下的原则,这种方法中,HTML的middleDiv(中栏)位列于leftDiv(左栏)之后,所以会在leftDiv之后加载,而middleDiv往往是页面的核心,需要优先加载展示给用户。

于是,我们思考将middleDiv放在HTML中的首位:

<body>    
    <div id="middleDiv">中栏</div>
    <div id="leftDiv">左栏</div>
    <div id="rightDiv">右栏</div>
</body>

CSS中,我们仍然设置middleDiv(中栏)的宽度为100% - 600px:

#middleDiv {
    width: calc(100% - 600px);
    ...
}

此时的界面如图所示:

示意图.png

可以看到,由于我们在HTML中将middleDiv(中栏)放在栏首位,所以浏览器窗口中,中栏显示在最前面。这时,我们需要为leftDiv(左栏)腾出空间,可以使用margin-left或padding-left。

margin和padding分别为盒模型的外边距和内边距,此处使用两者皆可,此处唯一的区别是padding会被底色填充而margin不会。因为background-color的填充区域为content+padding+border。

还有一点需要注意的是,padding值不能为负,对于需要取负值时,仅可使用margin。

为middleDiv(中栏)添加以下语句:

margin-left: 300px;

此时效果如下图所示:

示意图.png

可以看到,由于增加了300px的外边距,第一行的横向空间被middleDiv(中栏)和leftDiv(左栏)填满,rightDiv(右栏)被迫位列第二行。

此时,我们使用relative属性对左栏和右栏进行处理:

#leftDiv {
    position: relative;  /*相对定位*/
    left: calc(300px - 100%);  /*左移*/
    ...
}

#rightDiv {
    position: relative;
    top: -300px;  /*上移*/
    left: calc(100% - 300px);  /*右移*/
    ...
}

至此,我们在保证middleDiv(中栏)先行加载渲染的条件下,完成了三栏布局。基本思路为通过相对定位实现。

经典方法

CSS三栏布局的方法有很多种,其中最经典的方法莫过于圣杯布局和双飞翼布局。圣杯布局因形似圣杯而得名,即中栏为杯身,左右两栏为杯耳。双飞翼布局则是圣杯布局的一种改进,去掉了relative属性,并为主体部分增加了内容嵌套。

圣杯布局(In Search of the Holy Grail)

圣杯布局和双飞翼布局都需要在HTML中为div增加一层“容器(container)”。这个容器的目的主要是为了利用padding对中栏进行调整。

<body>  
    <div id="container">  
        <div id="middleDiv">中栏</div>
        <div id="leftDiv">左栏</div>
        <div id="rightDiv">右栏</div>
    </div>
</body>

首先,仍然设置float:left属性使div浮动,使其位于一行。

#leftDiv,#middleDiv,#rightDiv {
   float: left;
   ...
}

然后,将middleDiv(中栏)的宽度width设为100%:

#middleDiv {
    width: 100%;
    ...
}

得到如下图所示的布局:

示意图.png

此时,需要将leftDiv置于第一行左侧:

margin-left: -100%;  /* 左侧边界前移100% */

这样处理的结果是leftDiv(左栏)被置于第一行最左端,但会覆盖middleDiv(中栏)的部分内容。我们需要将中栏的内容从被覆盖的地方拉出来。一个简便的方法是对父容器container使用margin:

#container {
    margin: 0 300px 0 300px;
}

此处使用padding:0 300px 0 300px; 效果相同。

此时,leftDiv(左栏)也会受父容器的影响向右移动300px,仍然覆盖着middleDiv(中栏)的一部分,所以我们使用相对定位让其向左移动:

#leftDiv {
    position: relative;
    left: -300px;
    ...
}

此时的布局如下图所示:

示意图.png

对rightDiv(右栏)作类似处理:

#rightDiv {
    margin-left: -300px;  /*左侧边界前移300px*/
    position: relative;
    right: -300px;  /*右侧边界右移300px*/
    ...   
}

不要忘记为body设定最小宽度:

body {
    min-width: 800px;
}

至此完成。

可以看到,圣杯布局的实现思想是给div套上一个父容器,通过调整父容器的padding和div左右栏的相对定位来实现三栏布局。

双飞翼布局

双飞翼布局,源于淘宝UED,是圣杯布局的一种改进,或者说是另一种三栏实现思路。其创新点在于额外为middleDiv(中栏)增加一个子div存放其内容。

<body>  
    <div id="container">
        <div id="middleDiv">
            <div id="content">中栏</div>
        </div>
        <div id="leftDiv">左栏</div>
        <div id="rightDiv">右栏</div>
    </div>
</body>

仍然使用float属性来对div进行浮动:

#leftDiv,#middleDiv,#rightDiv {
   float: left;
   ...
}

与圣杯类似,设置middleDiv(中栏)宽度为100%,且将leftDiv(左栏)拉到最左侧,将rightDiv(右栏)作类似处理:

#middleDiv {
    width: 100%;
    ...
}

#leftDiv {
    margin-left: -100%;
}

#rightDiv {
    margin-left: -300px;
}

到这一步为止,双飞翼布局方法和圣杯CSS方法并不不同。

此时,由于双飞翼布局方法为middleDiv(中栏)单独添加了一个div存放其内容,所以对于中栏的处理,可以使用该div的margin属性:

#content {
    margin: 0 300px 0 300px;
}

此处使用padding:0 300px 0 300px; 效果相同。

同样,不要忘记为body设定最小宽度:

body {
    min-width: 800px;
}

至此完成。

可见,圣杯布局方法与双飞翼布局方法的区别在于圣杯布局采用相对位置属性(position:relative)来调整左栏和右栏位置,并使用margin/padding属性调整中栏。而双飞翼布局方法无需相对位置属性,而是采用为中栏内容创建div的方式,通过margin/padding来实现布局。

总结

本文探讨了三栏布局的CSS基本实现方法,首先以基本思路对三栏布局进行实现,发现不足,进行调整。文章第二部分阐述了流行的圣杯布局方法和双飞翼布局方法的细节和异同。除本文所述布局方法外,还存在绝对定位法、table布局法、网格布局法,以及十分方便的flex布局法等多种方法,各有利弊。

本文仅探讨了三栏布局的基本实现思路与方法,详细的实现过程希望能够帮助大家深入理解CSS。关于其他方法的讨论将在以后实际应用时进行总结。😊

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,737评论 1 92
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,450评论 1 45
  • 一、负边距在让元素产生偏移时和position: relative有什么区别? 负margin和position:...
    婷楼沐熙阅读 863评论 0 4
  • 一、负边距在让元素产生偏移时和position: relative有什么区别? 负边距在让元素产生偏移的时候其自身...
    dengpan阅读 305评论 0 0
  • CSS 定位问题 主要就是经典的绝对定位,相对定位问题。 10个文档学布局:通过十个例子讲解布局,主要涉及相对布局...
    强哥科技兴阅读 360评论 0 1