CSS 浮动:如何使浮动保持在它所属的文本附近?

CSS floats: how to keep the float near the text it belongs to?

我有一个包含多个步骤的程序。一些步骤附有图像。

    <p class="imagefloatright"><img src="step 1.png"/></p>
    <ol>
        <li>
          <p>Step 1</p>
          <p class="imagefloatright"><img src="step 2.png"/></p>
        </li>
        <li>
          <p>Step 2</p>
          <p>Step 3</p>
        </li>
    </ol>

和我的 CSS:

p.imagefloatright img {
    float: right;
    clear: both;
}

这是默认输出。图片不在它们所属的步骤中,步骤 2 的文本放在图片 1 旁边:

我希望属于第 2 步的图像与第 2 步垂直对齐:

过去,我通过在每个浮动图像前插入一个高度为 0 的全角块,在 XSL-FO 中实现了我想要的结果。

我可以使用 CSS 命令实现我想要的布局吗? 或者在将 CSS 应用于 HTML 之前,我是否需要在 HTML 中插入一个块?

你应该使用 clear 属性 而不是在 p 元素上,而是在你想停止浮动的地方创建另一个元素。

p.imagefloatright img {
    float: right;
}

.clear {
    clear:both;
}
<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p>Step 1</p>
<div class="clear"></div>
<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p>Step 2</p>
<div class="clear"></div>

顺便说一下,这是一个代码片段,显示了更好的步骤布局(从我的角度来看),这更符合逻辑,每个步骤都是一个块,图像和文本的位置正确。

p.imagefloatright {
    clear:both;
}

p.imagefloatright img {
    float: right;
}
<p class="imagefloatright">
  Step 1
   <img src="http://via.placeholder.com/80x80"/>
</p>

<p class="imagefloatright">
  Step 2
  <img src="http://via.placeholder.com/80x80"/>
</p>

如果您仍然希望在单独的 p 元素中包含文本,您可以将所有步骤作为 div 元素,其中包含适当样式的段落和图像。我还在 p 元素上应用 display:inline-block 以防止它占用整个宽度。您可以这样做或使用 span 而不是 p.

.imagefloatright {
    clear:both;
}

.imagefloatright p {
    display: inline-block;
    margin: 0;
}

.imagefloatright img {
    float: right;
}
<div class="imagefloatright">
  <p>Step 1</p>
   <img src="http://via.placeholder.com/80x80"/>
</div>

<div class="imagefloatright">
  <p>Step 2</p>
  <img src="http://via.placeholder.com/80x80"/>
</div>

clearfix 应该有帮助。 :

.clearfix:after {
  display: block;
  content: "";
  clear: both;
}

和html:

<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p class="clearfix">Step 1</p>
<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p class="clearfix">Step 2</p>
<p>Step 3</p>

如果每个有图片的步骤都只有一张图片,并且一张图片不会被超过一个步骤共享,您可以编写一个选择器让以下步骤清除每个浮动图像,但它非常严格:

p.imagefloatright img {
  clear: both;
  float: right;
}

p.imagefloatright + p:not(.imagefloatright) + p {
  clear: both;
}
<p class="imagefloatright"><img src="https://placehold.it/100x100"/></p>
<p>Step 1</p>
<p class="imagefloatright"><img src="https://placehold.it/100x100"/></p>
<p class="imagefloatright"><img src="https://placehold.it/100x100"/></p>
<p>Step 2</p>
<p>Step 3</p>

如果步骤和图像之间没有严格的 1 对 1 关系,那么您需要将 clear 属性 策略性地应用到特定步骤。

为什么不用伪元素?

p, .imagefloatright img { margin: 0 0 .25em; }

.imagefloatright img {
  float: right;
}

.imagefloatright::before {
  clear: both;
  content: '';
  display: block;
}
<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p>Step 1</p>
<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p>Step 2</p>
<p>Step 3</p>
<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p>Step 4</p>
<p>Step 5</p>

您必须使用 ::before::after 伪元素。另一种解决方案可能如下:

p, .imagefloatright img { margin: 0 0 .25em; }

.imagefloatright img {
  float: right;
}

.imagefloatright + p::after {
  clear: both;
  content: '';
  display: block;
}
<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p>Step 1</p>
<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p>Step 2</p>
<p>Step 3</p>
<p class="imagefloatright"><img src="http://via.placeholder.com/80x80"/></p>
<p>Step 4</p>
<p>Step 5</p>

以下所有步骤是否都属于图像?这取决于 ;)

你可以用这个

 <p>
    <span class="left">1</span>
       <img class="right"  src="http://via.placeholder.com/90x90" alt="">
  </p>

   <p>
    <span class="left">2</span>
       <img class="right"  src="http://via.placeholder.com/90x90" alt="">
  </p>

p{
  display:inline-block;
    margin-bottom:5px;
    width:100%;
}
p .left{
  float:left;
  margin-bottom:55px;
}
p .right{
 float:right;
}

https://jsfiddle.net/jlbarcelona/vcmdo7uy/106/

这里有一个使用 flexbox 的简单方法:

ol {
  list-style: none;
  padding:0;
  margin:0;
}

li {
  display: flex;
  /*for illustration*/
  border:1px solid;
  padding:5px;
}

img {
  margin-left: auto;
}
<ol>
  <li>
    Step 1
    <img src="https://placehold.it/100x100">
  </li>
  <li>
    Step 2
  </li>
  <li>
    Step 3
  </li>
  <li>
    Step 4
    <img src="https://placehold.it/100x100">
  </li>
</ol>

清除包含动态内容的浮动即。图像可以有动态高度,你需要清除父元素本身。

.imagefloatright {
  clear: both;
}
.imagefloatright img {
  float: right;
}

意味着你需要在包含浮动元素的元素上使用clear


为简洁起见,我将其重命名为:

.clearfix {
  clear: both;
}
.float-right {
  float: right;
}

HTML

<p class="clearfix"><img class="float-right" src="step 1.png"/></p>
<ol>
    <li>
      <p>Step 1</p>
      <p class="clearfix"><img class="float-right" src="step 2.png"/></p>
    </li>
    <li>
      <p>Step 2</p>
      <p>Step 3</p>
    </li>
</ol>

这是 demo.

这很容易做到。当您使用 css float 属性 时,您必须对其父元素使用溢出。你的情况:

p.imagefloatright{
   overflow: auto;
}

必须解决问题。详细了解 https://www.w3schools.com/css/css_float.asp

解决方案 1:使用 Flex

我建议使用 flexjustify-content: space-between 使用它的唯一缺点是如果您支持 IE10 等较旧的浏览器,那么您可以查看 https://caniuse.com/#search=flex 了解更多信息。

至于space-between就简单如根据MDN

The items are evenly distributed within the alignment container along the main axis. The spacing between each pair of adjacent items is the same. The first item is flush with the main-start edge, and the last item is flush with the main-end edge.

意思是,它将第一个 child 对齐到 parent 的开头,最后一个 child 对齐到结尾,其余的 space 被分割如果 children 存在,则它们在其余 children 中均等,如果 img 始终是最后一个 child,这将为您提供所需的布局,无论有多少 child div存在。

就我个人而言,我会发现使用 flex 是最方便也是最干净的方式之一 "position" 和 "layout" 跨页面的不同元素。

您可以在下面找到有效的代码 fiddle here

HTML

<ol class="step-list">
  <li class="step">
    <p>Step 1</p>
    <img src="https://placehold.it/150x150?text=Step1" alt="">
  </li>
  <li class="step">
    <p>Step 2</p>
  </li>
  <li class="step">
    <p>Step 3</p>
  </li>
  <li class="step">
    <p>Step 4</p>
    <img src="https://placehold.it/150x150?text=Step4" alt="">
  </li>
</ol>

CSS

.step-list {
  list-style: none;
}

.step {
  display: flex;
  justify-content: space-between;
}

解决方案 2:使用浮点数

您仍然可以使用 float,但在这种情况下,您需要清除 p 而不是 img 并将其也浮动。

由于包含元素的所有元素都是浮动的,因此向 li 标记添加 clearfix 很重要,不要崩溃到什么都没有你可以找到更多信息 here .

所以你的代码会喜欢这样,你可以找到一个有效的 fiddle here

HTML

<ol class="step-list">
  <li class="step">
    <p>Step 1</p>
    <img src="http://placehold.it/150x150?text=Step1" alt="">
  </li>
  <li class="step">
    <p>Step 2</p>
  </li>
  <li class="step">
    <p>Step 3</p>
  </li>
  <li class="step">
    <p>Step 4</p>
    <img src="http://placehold.it/150x150?text=Step4" alt="">
  </li>
</ol>

CSS

.step-list {
  list-style: none;
}

.step img {
  float: right;
}

.step p {
  float: left;
}

/*This is what is called a clearfix solution, for the floating problem*/
.step::after {
  content: "";
  display: block; 
  clear: both;
}

如果有任何不清楚的地方,请随时问我更多问题。

您可以在 li 标签中使用 after 伪元素来获取浮动元素的高度。此外,您还必须指定您只想使用 > 选择器浮动 li 标签内的元素。

ol {
  padding: 0;
}

li {
  padding: 10px;
  list-style: none;
  background: #eee;
  margin: 10px 0;
  width: auto;
}

li:after {
  content: '';
  display: table;
  clear: both;
}

li > p {
  width: 25%;
  float: left;
}

p {
  margin: 0;
}
<p><img src="http://fpoimg.com/300x300"/></p>
<ol>
  <li>
    <p>Step 1</p>
    <p><img src="http://fpoimg.com/300x300?text=Step1"/></p>
  </li>
  <li>
    <p>Step 2</p>
    <p>Step 3</p>
  </li>
</ol>