3

I got some strange behavior of float, thought it could be a simple but I am new in css and learning why and how questions.

here when I apply float element to the button it changes element's horizontal center alignment to top not sure why.

Any help would be much appreciated.

<h2>Image Text</h2>
<p>Center text in image:</p>

<div style="border: 1px solid red;">
  Text on left
  <span><button style="height:40px;">test</button></span>
</div>

enter image description here

Now add

<span ><button style="height:40px;float:right">test</button></span>

enter image description here

I know this problem can be solved in many ways, I am just wondering about the strange behavior of these element with float.

Regards MK

Community
  • 1
  • 1
Mohsin khan
  • 316
  • 3
  • 9

4 Answers4

0

If you add overflow: auto; and line-height: 40px; to that div, you get the desired result: Setting line-height to the parent element's heightvalue centers the (one-line) text, and overflow: auto makes the parent element wrap floated child elements, which otherwise is not the case (like in your question situation):

div {
  overflow: auto;
  line-height: 40px;
}

button {
  float: right;
}
<h2>Image Text</h2>
<p>Center text in image:</p>

<div style="border: 1px solid red;">
  Text on left
  <span><button style="height:40px;">test</button></span>
</div>
Johannes
  • 53,485
  • 15
  • 52
  • 104
  • that's look great with nice explanation. but what if i don't use overflow:auto here then still will appear correct ? – Mohsin khan Nov 22 '19 at 02:16
  • yes, true - that's because the parent's height is extended by the 40px height of the text line. So it also works that way. `overflow: auto;` will make sure the button really is *inside* the parent element, no matter what it's height is. If button height and text line-height are the same, setting line-height is sufficient. – Johannes Nov 22 '19 at 02:23
  • great! thank you for your time and explanation, much appreciated. have a great rest of the day! – Mohsin khan Nov 22 '19 at 02:30
0

Adding height to the container is not the best solution because if the content changes, then the height must also be changed. overflow:auto; on the parent will work, but it introduces design limitations as well.

The issue you are running into has to do with containers not automatically clearing contained floats. You need to use something called a clearfix on the container. There are many methods but the one I usually use employs a pseudo-element and works back to ie8:

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

With that CSS rule in your style sheet, you can then just add the class="clearfix" to any containers that you need to clear its own children.

For more info about floats, this is a good article (scroll down to 'The Great Collapse,' to learn about this particular issue you are facing), and to learn more about clearfixes, this article explains how various clearfixes work.

The advantage of using a pseudo-element for the clearfix is that we don't have to change the actual parent element's style at all, while changes to the parent's style could conflict with design requirements (like adding overflow:auto; which would work, but might conflict with a design where we needed to use overflow:hidden; or overflow:visible; on that parent element):

Here is your code with clearfix applied (note that I moved your style rules to CSS and added classes instead of inline style, which is generally good practice):

.container {
  border: 1px solid red;
}
button {
  height:40px;
}
.float-right {
  float: right;
}
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}
<h2>Image Text</h2>
<p>Center text in image:</p>

<div class="container clearfix">
  Text on left
  <span><button class="float-right">test</button></span>
</div>
Veneseme Tyras
  • 556
  • 1
  • 9
0

add a div height, and float to the button.(Also this can write as a inline CSS style )

div{height:40px;}

button { float: right;}
Chapa Ru
  • 1
  • 2
0

To understand what is happening you need to consider the fact that the default vertical alignment is baseline which is creating the first output.

Here is a better illustration to see the baseline:

.box {
  position:relative;
}
.box:before {
  content:"";
  position:absolute;
  bottom:14px;
  height:1px;
  background:blue;
  left:0;
  right:0;
}
<div style="border: 1px solid red;" class="box">
  Text on left
  <span><button style="height:40px;">test</button></span>
</div>

As you can clearly see both text are aligned the same and the button is somehow defining the baseline. Your text isn't centred like you may think.

Increase the font-size to see what happen:

.box {
  position:relative;
}
.box:before {
  content:"";
  position:absolute;
  bottom:14px;
  height:1px;
  background:blue;
  left:0;
  right:0;
}
<div style="border: 1px solid red;" class="box">
  <span >Text on left</span>
  <span><button style="height:40px;">test</button></span>
</div>

<div style="border: 1px solid red;" class="box">
  <span style="font-size:20px;">Text on left</span>
  <span><button style="height:40px;">test</button></span>
</div>

<div style="border: 1px solid red;" class="box">
  <span style="font-size:30px;">Text on left</span>
  <span><button style="height:40px;">test</button></span>
</div>

We still have the same baseline logic and not a centring logic.

Another example where the button is smaller in height

.box {
  position:relative;
}
.box:before {
  content:"";
  position:absolute;
  bottom:9px;
  height:1px;
  background:blue;
  left:0;
  right:0;
}
<div style="border: 1px solid red;" class="box">
  <span style="font-size:40px;">Text on left</span>
  <span><button style="height:20px;">test</button></span>
</div>

Still the same baseline thing.


You can change this behavior by changing the vertical alignment.

<div style="border: 1px solid red;" class="box">
  Text on left
  <span><button style="height:40px;vertical-align:bottom">test</button></span>
</div>

<div style="border: 1px solid red;" class="box">
  Text on left
  <span><button style="height:40px;vertical-align:top">test</button></span>
</div>

<div style="border: 1px solid red;" class="box">
  Text on left
  <span><button style="height:40px;vertical-align:sub">test</button></span>
</div>

Now if you float the button to the right, it will become a block level element and will no more affect the alignment of text that's why you obtain the following output:

<div style="border: 1px solid red;" class="box">
  Text on left
  <span><button style="height:40px;float:right;">test</button></span>
</div>

Even if you clear the float to fix the height issue the text will remain on the top and more precisely aligned on the baseline inside its line.

.box {
  overflow:auto;
}
<div style="border: 1px solid red;" class="box">
  Text on left
  <span><button style="height:40px;float:right;">test</button></span>
</div>

Now centring the text inside the red block is a common job and you can find a lot of question related to this. One solution like stated in the other answer is to set line-height which will simply increase the size of the line and move the baseline of the text around the center.

Some related questions to get more examples and detail:

Vertical-align aligns everything else except self

Vertical align not working on inline-block

Why is this inline-block element pushed downward?


Another important thing to notice is how the button is moved outside its span container. Add border to see this:

.box {
  overflow:auto;
}
<div style="border: 1px solid red;" class="box">
  Text on left
  <span style="border:2px solid blue;"><button style="height:40px;">test</button></span>
</div>

<div style="border: 1px solid red;" class="box">
  Text on left
  <span style="border:2px solid blue;"><button style="height:40px;float:right;">test</button></span>
</div>

Another related question to understand why: Can you float to the right of a span?

Temani Afif
  • 180,975
  • 14
  • 166
  • 216