需要将元素布局到右侧或左侧,以便文本环绕它?对于float
属性来说,这是一项简单的任务。但是,如果我们也希望将该元素(我们称之为图像)推到底部角之一,该怎么办?听起来有点棘手,对吧?我们可能需要 JavaScript?
不,几行(棘手的)CSS 就可以做到!以下仅使用 CSS 的解决方案将使您的图像粘贴到底部角,无论大小和内容如何。
调整包装元素的大小,见证神奇的效果
让我们剖析代码。
标记和布局
我们需要一个包装元素来包含所有内容,并且我们将对其使用flexbox。Flexbox 允许我们依赖默认的stretch
对齐方式,以便以后使用height: 100%
。
<div class="wrapper">
<div class="box">
<div class="float"><img></div>
Lorem ipsum dolor ...
</div>
</div>
.wrapper {
display: flex;
}
.float {
float: right;
height: 100%;
display: flex;
align-items: flex-end;
shape-outside: inset(calc(100% - 100px) 0 0);
}
.wrapper
内的.box
是我们的弹性项目。我们不需要对该框应用任何特定的 CSS。它定义了包装器的高度,并且同时被拉伸到相同的高度。此行为将为我们提供一个“参考高度”,子元素可以使用该高度。
来自规范
如果弹性项目具有
align-self: stretch
,则重新布局其内容,将此使用的大小视为其确定的交叉大小,以便可以解析百分比大小的子元素。
关键词是确定的,它允许我们在框元素内部安全地使用百分比(%)高度。
现在是浮动元素
我们的.float
元素将占据文本内容旁边的整个高度,这要归功于我们上面详细介绍的高度计算。在此元素内部,我们使用 flexbox 对齐方式将图像推到底部。

现在是真正的技巧,使用shape-outside
属性。以下是MDN 的定义
shape-outside CSS 属性定义了一个形状(可能是非矩形的),相邻的内联内容应围绕该形状换行。默认情况下,内联内容围绕其边距框换行;
shape-outside
提供了一种自定义此换行的方式,从而可以使文本围绕复杂对象而不是简单的框换行。
换句话说,shape-outside
设置内容围绕元素边界框流动的方向。
它采用许多值。其中一个是inset()
函数,再次,根据 MDN
定义一个内嵌矩形。当提供所有前四个参数时,它们分别表示从参考框向内开始的顶部、右侧、底部和左侧偏移量,这些偏移量定义了内嵌矩形边缘的位置。
因此,使用shape-outside: inset(calc(100% - X) 0 0)
,我们可以创建一个从图像顶部开始的内嵌矩形。顶部等于100% - X
,其中X
是图像高度,100%
是.float
元素的高度。这允许文本在图像顶部的可用空间内换行。这是响应式的,此外我们还可以轻松地在左侧和右侧之间切换(通过调整float
属性)
就是这样!唯一的主要警告是您需要知道图像的高度。
让我们优化标记
我们仍然可以稍微优化我们的代码并删除图像周围的额外包装器。
<div class="wrapper">
<div class="box">
<img class="float">
Lorem ipsum dolor ...
</div>
</div>
然后我们的 CSS 将变为
.wrapper {
display: flex;
}
.float {
float: right;
height: 100%;
width: 100px;
shape-outside: inset(calc(100% - 100px /*height */) 0 0);
object-fit: contain;
object-position: bottom;
}
由于我们删除了额外的包装器,因此我们需要另一种技术将图像放置到底部角。为此,我们使用object-fit
和object-position
,但必须显式指定图像的宽度。
使用此方法,我们需要知道图像的宽度和高度,这与前面的代码不同,在前面的代码中只需要高度。
想要更多?
我们可以进一步扩展此概念以适应更复杂的情况。例如,我们可以将图像浮动到右侧,但将其固定在框的中间,使用justify-content: center
:并通过将shape-outside
从inset(calc(100% - X) 0 0)
更改为inset(calc(50% - X/2) 0 0)
将我们的内嵌矩形调整到中间。
我们也可以在两个底部角浮动两个图像
这里没有什么复杂的东西。我只是简单地使用了相同的浮动元素两次,一次在右侧,一次在左侧。当我们可以在所有四个角放置图像时,为什么要止步于两个角呢?
这里采用了相同的基本思想,但我们也依赖于顶部图像的通用浮动功能。但是,您会注意到,这就是概念开始略微失效的地方,并且根据包含框的大小,我们会得到一些不需要的溢出。我们可以使.float
元素的高度大于 100%,并应用一些“魔法数字”通过调整图像的填充和边距来使事情变得平滑。
您知道shape-outside
接受radial-gradient()
作为值吗?我们可以用它来放置如下所示的圆形图像
渐变的透明部分是文本可以进入的可用空间。您可能已经注意到,我们也对图像应用了border-radius
。shape-outside
属性只会影响.float
元素,我们需要手动调整图像的形状以遵循shape-outside
定义的形状。
既然我们已经这样做了,让我们将其与我们之前使用justify-content: center
将图像固定到框垂直中心的示例结合起来。
另一个radial-gradient()
以及另一个border-radius
配置。
我们可以改用linear-gradient()
来为包装区域制作三角形形状
这与我们用于radial-gradient()
的想法相同。最大的区别是我们使用clip-path
而不是border-radius
来裁剪我们的图像。
并且,既然我们对其他元素进行了此操作,让我们使用justify-content: center
的想法将图像固定到框右侧边缘的垂直中心。
我们在上面的演示中使用了conic-gradient()
和shape-outside
来定义三角形形状,并使用clip-path
在图像上获得类似的形状。
如果图像仅用于装饰(如果在 HTML 中不需要它用于 SEO 目的),则所有这些示例仍然可以使用更少的代码进行优化。让我们用伪元素替换.float
元素,并改为将图像应用为背景
我们使用mask
来显示我们需要的图像部分,并且,猜猜看,它使用了与shape-outside
相同的值!因此,我们所要做的就是为形状定义一个值。
就是这样!
这里有很多可能性,不仅可以将矩形放置在角上,还可以使用基本相同的代码结构将任何类型的形状放置在任何位置。我们只需要
- 调整
shape-outside
属性以定义形状 - 对图像应用一些样式以遵循先前定义的形状或如果我们使用伪元素版本,则对
mask
应用相同的值
然后所有内容都保持在原位,即使在响应式设计中也是如此。
精彩的文章。这让我充满信心,相信我将永远不必再使用
float
了。确实是一次很棒的样式和技巧练习!但我们能否确定一种语言应该如此复杂才能实现这一点?我认为它应该提供更简单的方法来做到这一点,而不是这种魔法!
这实际上是一个非常简单的方法来实现它 :) 它只有 6 行 CSS 代码。如果您搜索相同主题,您会发现更复杂的代码只能“近似”实现这一点(我们不讨论那些使用 JS 的代码)
对于一些老读者来说,这篇文章可能会引发一些
float
的创伤后应激障碍。我不记得上一次我能够保证我的图片高度是什么时候了。
有没有什么想法可以处理响应式图片?
我认为你唯一的方法是明确指定高度:https://jsfiddle.net/8aoryLju/ 它将保持响应性,但具有固定高度
所以在前几个例子中,其中
float
类宽度为100%……是什么阻止了图像上方的文本——以及浮动下方的文本——被“覆盖”并且无法选择?是shape-outside
属性起作用了吗?我遇到了两个情况,浮动元素的不可见部分覆盖了表单元素,导致无法点击。抱歉,我的意思是
height
为100%。确实,你说得对。这是关于我使用遮罩的最后一个例子。在这种情况下,堆叠顺序将使浮动元素位于文本上方,从而阻止文本选择(或任何交互)。
我没有注意,因为它在其他示例中没有发生。
要避免这种情况,只需向浮动元素添加
pointer-events:none
。感谢这个很棒的例子!我唯一注意到的问题是,外部元素和.float元素上的height:100%;也包含图像的高度。当框的内容高度小于图像时,会导致元素底部出现一些“空白”。你可以在这个fiddle中看到我的意思,在按钮和容器边缘之间有空间:https://jsfiddle.net/s8jqmb6v/
如果height:100%不包含图像高度,图像将稍微向上推一点,以便h3也会换行。
希望你多少能理解我的意思,并能提供一些提示/解决方法?
不幸的是,你遇到了这种技术的局限性之一。当图像相对于你的内容足够大时,你会遇到这样的问题,因为高度计算有点复杂。
抱歉,对于这种情况我也不知道好的解决方法。可能将来会找到一个。
谢谢!花了几个小时尝试实现这个目标,直到我最终找到了这个页面!!!
有了它,我能够在几分钟内重构我的页面使其工作。太棒了!
现在似乎可以在无需将图像包装在.box中就能实现相同的结果,方法是在img本身添加`height: 100%; object-fit: cover; object-position: bottom;`。
*object-fit: contain;
很棒的文章!我通过Stackoverflow找到了它。之前我用Javascript捣鼓过,但你证明了如果要浮动的元素的高度已知,则无需使用它。
如果不知道怎么办?例如,带有一些标题的图片元素。是否也可以不用JS实现?
实际上,有一个纯CSS解决方案,即使在Internet Explorer 10和11中也能工作!
如果你知道图像的纵横比,则可以使用百分比宽度设置图像。不幸的是,百分比高度不起作用。
只需左右移动鼠标调整div的大小(之所以这样做是因为IE不支持
resize:
属性)不幸的是,它并不总是可靠。在某些宽度下,某些单词可能会被截断——包装元素不会根据需要增加其高度。这在我的项目中经常发生,但我能够在文章的示例中重现它。它可以在Firefox和Chrome上重现,我认为更大的图像更容易导致这种情况。只需缓慢更改包装器的宽度,直到最后一个单词换行,并且存在一个宽度,即存在换行符,但包装器仍处于其先前的高度。