Css权威指南(4th,第四版中文翻译)-10.Floating
很长一段时间里面,floated元素是作为网页布局的基石。
浮动
在过去只能浮动图片,table。而CSS可以让所有元素都支持浮动。通过float属性来支持:

比如想要把image浮动到左边,可以使用下面的方式:
<img src="b4.gif" style="float: left;" alt="b4">

浮动的元素
浮动元素和一般的元素有几个区别。第一,他从正常的文档流里面跳出来了。另外虽然有自己的放置位置,不过浮动元素还是会影响文档中的其他元素。因为当一个元素浮动后,周围的其他元素就需要浮动环绕着它。这要浮动图片的时候是用的比较多的,不过同样可以作用于段落。在下图留着那个,可以比较清晰的看到这一效果:
p.aside {float: right; width: 15em; margin: 0 1em 1em; padding: 0.25em; border: 1px solid;}

一个重要的关于浮动元素的点就是margin不会合并。如果给一张图片20px的margin,那么最终的显示效果其margin至少是20px,比如下面的例子:
p img {float: left; margin: 25px;}

另外值得注意的就是对于不可替代的元素,必须申明其width。不然的话浏览器会以默认的1个字符的宽度显示:

浮动的细节
在浮动中有一个专有名词叫容器盒子(containing block)。浮动元素的容器盒子其实就是离他最近的一个block父元素。另外有一系列的规则用于设置浮动元素的位置布局:
- 浮动元素的左右外部边界必须在容器盒子的左右内边界内。
其实也很好理解,既然是容器,那么浮动元素肯定不能超过这个容器的大小,如下图所示:

- 浮动元素不准交叠

-
浮动元素的上边界不准高于所有早期的floating和block元素
image.png
-
浮动元素必须尽量从上往下排
应用的行为
基于上面的标准,我们可以窥见浮动元素预计排布的规律。但我们首要要解决的就是浮动元素高于父元素的情况。
举例来说:

上面看上去正常么,你可能觉得再正常不过,而实际是因为没有加背景,来看下:

而且如果浮动元素内嵌套浮动元素,也会出现更加奇怪的效果:

负的margin
按照之前的介绍,可以想见负的margin会导致元素跳出父元素框。来看个例子,我们想left和top的margin都设置为-15px,效果如下图所示:

Clearing
在进入shape的说明之前,我们首先来看看如果来放置浮动内容在浮动元素间穿过。比如:

这就需要clear属性的使用:

举个例子,为了确保所有的h3元素不放在向左浮动元素的右边,我们需要这样定义:
h3 {clear: left;}
这样就可以确保h3元素的左边不会有浮动的元素。

如果为了保证两边都没有浮动元素则可以使用both:
h3 {clear: both;}

如果设置了none,那么就会允许元素左右两边都可以有浮动元素:
h3 {clear: both;}
<h3 style="clear: none;">What's With All The Latin?</h3>

浮动的形状 Shapes
在了解了基本的形状以后,我们开关注下浮动的形状,它是支持非矩形的图形的。
生成一个形状
如果要定义浮动内容的形状,首先需要定义的就是shape-outside:

none的话就是没有形状,浏览器会采取默认的margin box。
首先我们来通过图片定义浮动元素的形状,这也是最简单的改变形状的方式之一。来看个月亮的例子:
img.lunar {float: left; shape-outside: url(moon.png);}
<img class="lunar" src="moon.png">

值得注意的就是文字的话会在浮动元素的一边填充图片中背景透明的区域,比如上图和下图:
p {text-align: right;}
img.lunar {float: right; shape-outside: url(moon.png);}

那如果图片没有透明设置呢,比如JPEG,那就只能显示一个方块了。必须具有alpha通道才可以。
下面来看看<basic-shape>和<shape-box>的值,basic shape有下面几种:
- inset()
- circle()
- ellipse()
- polygon()
而shape box 有下面这几种:
- margin-box
- border-box
- padding-box
- content-box
下面是不同的示例:

默认是margin box。
inset的形状
如果之前用过border 图片中的clip属性,那么inset其实是很类似的。没用过也没关系,本身并不复杂。其定义的就是每条边朝内的距离。举个例子:
shape-outside: inset(2.5em);
这个会从外面的margin box向里推进2.5em,而如果要设置从哪个box往里面推,可以使用对应的box:
shape-outside: inset(2.5em) padding-box;

另外对于inset里面的值,可以用传统的CSS的赋值方式,1-4个都可以:
shape-outside: inset(23%);
shape-outside: inset(23% 23% 23% 23%); /* same as previous */
shape-outside: inset(1em 13%);
shape-outside: inset(1em 13% 1em 13%); /* same as previous */
shape-outside: inset(10px 0.5em 15px);
shape-outside: inset(10px 0.5em 15px 0.5em); /* same as previous */
同时边角也可以round,跟border-radius类似:
shape-outside: inset(7%) round 5px;
shape-outside: inset(7% round 0.5em/5px);

圆形和椭圆形
这两种形状的定义都是类似的,本来圆形就是特殊的椭圆。
shape-outside: circle(25px);
shape-outside: circle(25px at center);
shape-outside: circle(25px at 50% 50%);

不过半径如果超过的边框的大小,有时候也会出现问题:
img {shape-outside: circle(25px at center);}
img#small {height: 30px; width: 35px;}

这时候我们可以通过相关的值来控制边界:
shape-outside: circle(closest-side);
shape-outside: circle(farthest-side at top left);
shape-outside: circle(closest-side at 25% 40px);
shape-outside: circle(farthest-side at 25% 50%);

而对于椭圆来说,最大的区别就是要定义两个半径:

对于百分比值来说,其标准为box的两边:

多边形
多边形的定义其实就是点的定义,每个点以逗号分隔,可以定义任意多个点,每个点表明其x-y坐标:
polygon(25px 0, 50px 25px, 25px 50px, 0 25px)
而多边形是不允许超出box shape的边界的,超过了也会被clip掉:

另外我们还可以控制填充颜色的规则:
polygon(nonzero, 51% 0%, 83% 100%, 0 38%, 100% 38%, 20% 100%)
polygon(evenodd, 51% 0%, 83% 100%, 0 38%, 100% 38%, 20% 100%)

控制shape的图片透明度
之前我们说到浮动元素只有透明区域是可以侵入的,但是我们可以通过shape-image-threshold来控制:

这一属性可以让不同透明度的范围暴露在文字中,比如设置个0.5:

添加一个shape的margin
浮动元素的形状定义好后,我们其实可以加个margin的通过:

例如:
img {float: left; margin: 0; shape-outside: url(star.svg);
border: 1px solid hsla(0,100%,50%,0.25);}
#one {shape-margin: 0;}
#two {shape-margin: 1.5em;}
#thr (shape-margin: 10%;}

同时可以对不同的边进行单独的设置:
#two {shape-margin: 1.5em; margin: 0 1.5em 1.5em 0;}
#thr (shape-margin: 10%; margin: 0 10% 10% 0;}

小结
浮动作为CSS中比较基础的一个方面,但同样非常有用和强大。借助它我们实现了文字的环绕显示,而且形状也不仅仅限于矩形了。