Open creeperyang opened 9 years ago
position: absolute
的 containing block 问题position: absolute
的元素的包含块(containing block) 总是最近定位的祖先元素(nearest positioned ancestor)所在的包含块。所谓定位,即position
是relative, absolute, fixed
。
如果没有最近定位的祖先,那么包含块就是 initial containing block
。问题的难点就在谁是 initial containing block
?
在我的(可能包括很多人)潜意识里,initial containing block
显然就是<body>
。可以看个例子:
<body>
<style>
body{height: 200vh; background-color: green;}
.demo{position: absolute; top: 0; left: 0; bottom: 0; right: 0; background-color: yellow;}
</style>
<div class="demo"></div>
</body>
可以看到,背景黄色的.demo
占满整个窗口。调整body高度,.demo
的高度始终不变,即跟<body>
无关。所以<body>
不是 initial containing block
。然后<html>
是么?是(html所在的包含块):
http://www.w3.org/TR/CSS2/visudet.html#containing-block-details:
The containing block in which the root element lives is a rectangle called the initial containing block. For continuous media, it has the dimensions of the viewport and is anchored at the canvas origin; it is the page area for paged media. The 'direction' property of the initial containing block is the same as for the root element.
概念有点晦涩,就屏幕媒体而言,
initial containing block
是一个长方形,尺寸和视口(窗口,window)一致,定位于画布(绘制整个文档的canvas,不要与<canvas>
元素混淆)的起点。 可以看作(但不是)没有滚动时的窗口。
所以我们可以看到例子中.demo
恰好铺满窗口,不论<html>/<body>
怎么变动。
为什么通过position: absolute; top: 0; bottom: 0;
来确认initial containing block
?
当同时指定绝对定位元素的top
和bottom
,且height
没有指定,或者是auto
/100%
,那么top
和bottom
都会起作用,指定对包含块的上下距离。通过这个原理,我们在以上例子中,调整body高度而.demo
的高度不变,确认body不是initial containing block
。
-webkit-overflow-scrolling
https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-overflow-scrolling
-webkit-overflow-scrolling: touch;
在触屏设备上采用基于动量(momentum-based)的滚动。直觉上就是手指离开屏幕后滚动不会立即停止,会根据你之前的滑动速度继续减速滚动一段距离,和一般的 natvie 应用上的滚动类似。
overflow: auto;
在某些情况下总是出现滚动条(内容高度不大于容器高度)div(class='container')
canvas(class='content')
当 container
和 content
的高度相同,而 container
设置 overflow: auto;
,为什么滚动条总是出现?
以下是 codepen 地址:
See the Pen mwqXPx by creeper (@creeper) on CodePen.
我们可以看到, 在容器和内容等高,当内容标签是 <canvas>
时,即使设定 overflow: auto;
也总是出现滚动条。
当我们设定 <canvas>
为 display: block;
时,上述情况消失,可见,应该和 <canvas>
默认内联布局有关。
原因:
具体可查阅CSS深入理解vertical-align和line-height的基友关系。
简单说,就是和默认的line-height/vertical-align
值有关。默认情况下,vertical-align:baseline
导致需要保留容纳descenders的距离,这就是图片下面多出的一段空白。
除了设定 <canvas>
为 display: block;
来解决问题,也同样可以设置容器 font-size: 0;
等方式来解决。
hybrid 开发中碰到的一个 flexbox 布局问题:https://codepen.io/creeper/pen/evVOQR
上中下三栏布局中,上下固定高,中间flex-grow: 1
(中间块 overflow: auto
,其内容较多时可滚动),结果导致上下被挤压。
原因就是 flexbox 布局中剩余空间分配的默认规则跟我们小的不太一样,我们要正确设置 flex-shrink/flex-grow/flex-basis
。
http://zhoon.github.io/css3/2014/08/23/flex.html 这篇文章可以一看,对剩余空间分配讲解的比较清楚:
具备flex环境的父容器,通常是有一条主轴和一条侧轴,默认情况下主轴就是水平从左向右的,侧轴是垂直从上到下的(类似书写模式)。 剩余空间就是父容器在主轴的方向上还有多少可用的空间。
<div class="container">
<span class="B1"></span>
<span class="B2"></span>
<span class="B3"></span>
</div>
假设 container
高度 500px ,那么剩余高度就是 500px - B1.width - B2.width - B3.width
。
flex-grow 就是索取父容器的剩余空间,默认值是0 ,就是不索取剩余空间。
接上面的例子,假设 B1/B2/B3 的 width 都是 100px 。因为默认值是 0,那么剩余的 200px 不会被占用。
flex-grow: 1
,那么剩余 200px 都被 B2 占用,B2 变成 300px。flex-grow: 1
,B2 的 flex-grow: 2
,那么 B1 和 B2 都参与剩余空间瓜分,B1 瓜分 200px / 3 * 1
,B2 瓜分 200px / 3 * 2
。flex-basis 用于和父容器预约空间(预约剩下的归入剩余空间),默认值是 auto,即由自身内容决定空间占用(长度)。
讲到现在,都是容器长度超过子元素长度和(flex 默认不换行,这里先不考虑 flex-wrap),如果小于会怎么样?小于的话怎么计算剩余空间?
这里就要说到 flex-shrink 了。
flex-shrink 属性用于设置 flexbox 的收缩比率, 默认值是 1 ,即子元素长度和超过容器时默认压缩。
接上面的例子:
设置各自的长度为:
container: 500px;
B1: 300px;
B2: 160px;
B3: 120px;
则
剩余空间是 500 - 300 - 160 - 120 = -80px; 要进行压缩(假设没有设置 flex-wrap)。
因为 flex-shrink 默认 1,
则最终:
B1: 258.63px; 缩小 41.37 = 80 * (300 / 580)
B2: 137.94px; 缩小 22.06 = 80 * (160 / 580)
B3: 103.45px; 缩小 16.55 = 80 * (120 / 580)
如果我们把 B1 的 flex-shrink 设为 2,则最终:
B1: 245.45px; 缩小 54.55 = 80 * ((300 + 300) / (580 + 300))
B2: 145.45px; 缩小 22.06 = 80 * (160 / (580 + 300))
B3: 109.09px; 缩小 16.55 = 80 * (120 / (580 + 300))
同事碰到这样一个问题:如下代码,chrome 查看开发工具,发现 .btn
里的样式起效了,.btn.disabled
却完全不起作用。
<button class="btn disabled"/>
.btn {
rules
}
.btn.disabled {
rules
}
试过各种办法,包括重写 rules 都没用。然后同事删掉所有 css 代码重写,终于没这个问题了。
所以到底什么原因?
结合以前碰到过的问题,我觉得应该是字符显示/编码问题。让同事恢复到有问题的版本,复制选择符测试:
`.btn {`.charCodeAt(4)
// 32
`.btn.disabled {`.charCodeAt(13)
// 132
所以一切清晰了,.btn.disabled
后面不是空格,虽然它视觉上是个空格。
最后一句话,有时不要相信你看到的。
<a>
标签不能嵌套<a>
标签嵌套是非法的,详见 Are you allowed to nest a link inside of a link?
如果嵌套,浏览器将不会“正确”解析元素层级关系:外部的 <a>
会在内部 <a>
前提前闭合。 参见https://codepen.io/creeperyang/pen/LmQwzz
等宽/等高布局是常常碰到的需求,flexbox 也可以很容易地满足需求;但在需要兼容IE9等不能使用 flexbox 的情况下,table 布局是个不错的选择(兼容 IE8)。
table-cell 天然可以等高,但等宽时需注意给 container 加一个 table-layout: fixed;
。
demo: https://gist.github.com/creeperyang/dcf0ad40624dec5e61441957cb061f2a
link: https://stackoverflow.com/questions/10525744/css-table-cell-equal-width
各个时期垂直居中的方法不尽相同,在 flexbox 之后,我以为不会再重提这个问题,毕竟在 flexbox 下居中实在太容易了。
但没想到,很快旧事重提...
在 Android 中,
.box {
display: flex;
align-items: center;
justify-content: center;
}
以上代码并不能使box
内的文字垂直居中。解决方案:https://www.zhihu.com/question/39516424/answer/274374076?hb_wx_block=0
.box {
display: flex;
align-items: center;
justify-content: center;
font-family: PingFangSC-Regular, STHeiti STXihei, Microsoft YaHei, Microsoft JhengHei, miui;
}
目前来看,不居中的原因和安卓计算字体行高的规则有关,暂时设置字体为中文字体可解决。
<button>
使用 flexbox 时在 iOS 9 文字不居中问题出在某些版本的 safari 不支持 button 作为 flexbox 布局的 container。
修复方法:
display: -webkit-box;
-webkit-box-orient: horizontal;
参考 https://blog.csdn.net/u012076852/article/details/52062553
可以通过使用padding,或者 line-height: 1px
来 hack。
input {
height: 40px;
line-height: 1px;
}
目前一个比较主流的响应式布局方案就是使用 rem,在微信中查看页面时发现布局错乱。查找原因时发现 html 的 font-size 实际值比设置的值要大,最后定位到是微信设置中放大了字体。
解决方法:
html {
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100%!important;
}
broder-radius: 50%
非完美圆(正圆)的问题问题依然与使用 rem 有关,使用 rem 后某些尺寸下必然产生元素实际宽高的小数点问题,不同浏览器对小于1px的处理方式不同(四舍五入或直接丢弃等等),这就造成无法正圆。
解决方案,采用 transform 缩放来避免/减轻非正圆的情况:
.circle {
width: 2rem; // 放大10倍
height: 2rem;
border-radius: 50%;
transform scale(.1); // 再缩小回来
transform-origin: center;
}
<input>
使用伪元素无效结论:replaced element 不支持伪元素。
像 img/input 这些替换元素,本身就不支持伪元素。参考:
<textarea>
随文字输入自动适应高度https://codepen.io/vsync/pen/czgrf
原理是根据 scrollHeight 来设置 height;缺点是删除文字后不太好处理高度自动缩减的问题。
今天遇到并讨论了一个CSS相关的问题,很有意思,并更正了我的某些错误概念。想以问答的形式记录下,发现只有 JavaScript问题集锦,于是干脆就新开了一个issue,以后所有的HTML与CSS相关问题都记录在这里。