转载自十年灯 http://jo2.org/CSS-auto-adapt-width/
分享好文章, 也是给自己做个积累.
反过来也可以: 左侧宽度固定, 右侧自适应. 不管是左是右, 反正就是一边宽度固定, 一边宽度自适应.
这种布局比较常见, 博客园很多默认主题就是这种. 一般情况下, 这种布局中宽度固定的区域是侧边栏, 而自适应的区域是主体内容区 -- 相信把侧边栏搞成自适应的人很少吧?
要实现这种布局, 也算比较简单. 我们先给出 html 结构:
- <div id="wrap">
- <div id="sidebar" style="height:240px;"> 固定宽度区 </div>
- <div id="content" style="height:340px;"> 自适应区 </div>
- </div>
- <div id="footer"> 后面的一个 DIV, 以确保前面的定位不会导致后面的变形 </div>
代码中的 #wrap 的 div, 是用来包裹我们要定位的这两个区的; 他后面还有个 #footer, 用来测试在前面的定位搞定后会不会导致后面的 div 错位 -- 如果错位了, 那证明我们的定位方法必须改进.
下面列举几个常见的方法:
1, 固定宽度区浮动, 自适应区不设宽度而设置 margin
我们拿右边定宽左边自适应来做示范, CSS 代码如下:
- wrap {
- overflow: hidden; *zoom: 1;
- }
- content ,#sidebar {
- background-color: #eee;
- }
- sidebar {
- float: right; width: 300px;
- }
- content {
- margin-right: 310px;
- }
- footer {background-color: #f00;color:#fff; margin-top: 1em}
其中, sidebar 让他浮动, 并设置了一个宽度; 而 content 没有设置宽度.
大家要注意 html 中必须使用 div 标签, 不要妄图使用什么 p 标签来达到目的. 因为 div 有个默认属性, 即如果不设置宽度, 那他会自动填满他的父标签的宽度. 这里的 content 就是例子.
当然我们不能让他填满了, 填满了他就不能和 sidebar 保持同一行了. 我们给他设置一个 margin. 由于 sidebar 在右边, 所以我们设置 content 的 margin-right 值, 值比 sidebar 的宽度大一点点 -- 以便区分他们的范围. 例子中是 310.
假设 content 的默认宽度是 100%, 那么他设置了 margin 后, 他的宽度就变成了 100%-310, 此时 content 发现自己的宽度可以与 sidebar 挤在同一行了, 于是他就上来了.
而宽度 100% 是相对于他的父标签来的, 如果我们改变了他父标签的宽度, 那 content 的宽度也就会变 -- 比如我们把浏览器窗口缩小, 那 wrap 的宽度就会变小, 而 content 的宽度也就变小 -- 但, 他的实际宽度 100%-310 始终是不会变的.
这个方法看起来很完美, 只要我们记得清除浮动 (这里我用了最简单的方法), 那 footer 也不会错位. 而且无论 content 和 sidebar 谁更长, 都不会对布局造成影响.
但实际上这个方法有个很老火的限制 --html 中 sidebar 必须在 content 之前!
但我需要 sidebar 在 content 之后! 因为我的 content 里面才是网页的主要内容, 我不想主要内容反而排在次要内容后面.
但如果 sidebar 在 content 之后, 那上面的一切都会化为泡影.
可能有的人不理解, 说你干嘛非要 sidebar 在后面呢? 这个问题说来话长, 反正问题就是 --content 必须在 sidebar 之前, 但 content 宽度要自适应, 怎么办?
下面有两个办法, 不过我们先把 html 结构改成我们想要的样子:
- <div id="wrap">
- <div id="content" style="height:340px;"> 自适应区, 在前面 </div>
- <div id="sidebar" style="height:240px;"> 固定宽度区 </div>
- </div>
2, 固定宽度区使用绝对定位, 自适应区照例设置 margin
我们把 sidebar 扔掉, 只对 content 设置 margin, 那么我们会发现 content 的宽度就已经变成自适应了 -- 于是 content 对 sidebar 说, 我的宽度, 与你无关.
content 很容易就搞定了, 此时来看看 sidebar, 他迫不得已抛弃了 float. 我们来看看 sidebar 的特点: 在右边, 宽度 300, 他的定位对 content 不影响 -- 很明显, 一个绝对主义分子诞生了.
于是我们的 css 如下:
- wrap {
- *zoom: 1; position: relative;
- }
- sidebar {
- width: 300px; position: absolute; right: 0; top: 0;
- }
- content {
- margin-right: 310px;
- }
这段 css 中要注意给 wrap 加上了相对定位, 以免 sidebar 太绝对了跑到整个网页的右上角而不是 wrap 的右上角.
好像完成了? 在没有看 footer 的表现时, 我很欣慰. 我们来把 sidebar 加长 -- 增长 100px! 不要一年, 只要一条内裤! 哦,,, 只要一句代码.
但是, footer 怎么还是在那儿呢? 怎么没有自动往下走呢? footer 说 -- 我不给绝对主义者让位!
其实这与 footer 无关, 而是因为 wrap 对 sidebar 的无视造成的 -- 你再长, 我还是没感觉.
看来这种定位方式只能满足 sidebar 自己, 但对他的兄弟们却毫无益处.
3,float 与 margin 齐上阵
经过前面的教训, 我们重新确立了这个自适应宽度布局必须要达成的条件:
sidebar 宽度固定, content 宽度自适应
content 要在 sidebar 之前
后面的元素要能正常定位, 不能受影响
由于绝对定位会让其他元素无视他的存在, 所以绝对定位的方式必须抛弃.
如果 content 和 sidebar 一样, 都用 float, 那 content 的自适应宽度就没戏了; 如果不给 content 加 float, 那 sidebar 又会跑到下一行去.
所以, 最终我决定: float 与 margin 都用.
我打算把 content 的宽度设为 100%, 然后设置 float:left, 最后把他向左移动 310, 以便于 sidebar 能挤上来.
但这么一来 content 里面的内容也会跟着左移 310, 导致被遮住了, 所以我们要把他重新挤出来. 为了好挤, 我用了一个额外的 div 包裹住内容, 所以 html 结构变成了这种样子:
- <div id="wrap">
- <div id="content" style="height:140px;">
- <div id="contentb">
content 自适应区, 在前面
- </div>
- </div>
- <div id="sidebar" style="height:240px;">sidebar 固定宽度区 </div>
- </div>
css 则变成这样:
- sidebar {
- width: 300px; float: right;
- }
- content {
- margin-left: -310px; float: left; width: 100%;
- }
- contentb {
- margin-left: 310px;
- }
这样一改, 真正的 "content" 就变成了 contentb, 他的宽度跟以前的 content 一样, 是 100%-310.
大家可能注意到了代码中的两个 margin-left, 一个 - 310px 一个 310px, 最后结合起来相当于什么都没干, 着实蛋疼. 但他确实解决了 content 与 sidebar 的顺序问题.
这个方法的缺点就是: 太怪异, 以及额外多了一层 div.
4, 标准浏览器的方法
当然, 以不折腾人为标准的 w3c 标准早就为我们提供了制作这种自适应宽度的标准方法. 那就简单了: 把 wrap 设为 display:table 并指定宽度 100%, 然后把 content+sidebar 设为 display:table-cell; 然后只给 sidebar 指定一个宽度, 那么 content 的宽度就变成自适应了.
代码很少, 而且不会有额外标签. 不过这是 IE7 都无效的方法.
------- 割尾巴 ---------
如果不考虑 ie7 及以下版本, 则使用标准方法; 如果不在意 sidebar 与 content 的顺序, 则用第一种方法; 否则用第 3 种方法.
以上代码都没在 IE6 测试, 有问题不负责解释. 个人觉得, 让 IE6 寿终正寝的办法就是 -- 从此不再理他.
来源: http://www.qdfuns.com/article/47855/0c1edcc5588ad36ea21676f372e1ab84.html