76

Every time I try to do something seemingly-simple in CSS, it doesn't work.

I have a content div that contains a 460x160 image. All I want to do is position the image at the bottom-right corner and wrap my text around it.

<div id="contents">
    <img src="..." />
    text text text text text text ...
</div>

So I want it to look like:

------------------
| text text text |
| text text text |
| text text -----|
| text text |    |
------------------

Doing it with a top-left or top-right image is cake:

#contents img { float:right; }

------------------
| text text |    |
| text text -----|
| text text text |
| text text text |
------------------

Now how do I push that to the bottom? The best I've come up with so far are:

#contents img { float:right; margin-top: 90%} // really needs to be 100%-160px

------------------
| text text      |
| text text      |
| text text -----|
| text text |    |
------------------

In this case the text does not print in the margin, so there is white space above the image.

#contents { position:relative; }
#contents img { position:absolute; right:0; bottom:0; }

-or-

// move the img tag under the text in the html and:
#contents img { float:right; margin-top:-160; }

------------------
| text text text |
| text text text |
| text text -----|
| text text | te |
------------------

In this case the text prints over or under the image.

So... how can I accomplish this?

TylerH
  • 20,799
  • 66
  • 75
  • 101
CodingWithSpike
  • 42,906
  • 18
  • 101
  • 138
  • does the div has a fixed dimension? Does the amount of text changes? – user58670 Feb 01 '09 at 00:18
  • +1 just cos I can't solve this (yet!). Best I've done is absolutely position the image at the bottom right but the text doesn't wrap around it then. – cletus Feb 01 '09 at 00:23
  • Additinal note: Text is unknown length. Its read out of a DB. This prevents me from dropping the img into the middle of the text. – CodingWithSpike Feb 01 '09 at 00:51
  • Things have now changed, there is the new CSS shapes spec. Have a look at this for a modern approach (at this date still lacking full browser support) and a demo of the basic solution suggested in this thread : http://stackoverflow.com/a/32706706/3168107. – Shikkediel Sep 24 '15 at 16:52
  • FYI, This can be accomplished very easily. See my answer here with examples: https://stackoverflow.com/a/54765318/3334390 – Chadwick Meyer Feb 19 '19 at 11:50

9 Answers9

34

It sure seems to have been asked before (2003), and before (2002), or before (2005)

The last link actually suggest a javascript-based solution, but for a fixed (i.e. non fluid) solution.

It is consistent however, with other advices found

The only way to do that is to put the floated element somewhere in the middle of the text. It's impossible to get it perfect all of the time.

Or this one:

It consists of floating a vertical "pusher" element (such as img, but it's probably smarter to just use an empty div), then floating the desired object under it, using the clear property. The major problem with this method is you still have to know how many lines there are of text. It makes things MUCH easier though, and could definitely be coded with javascript, just need to change the height of the "pusher" to the height of the container minus the height of the float (assuming your container isn't fixed/min height).

Anyway, as discussed in this thread, there is no easy solution...


Cletus mentions in the comments this thread from 2003, which states once again the fact it can not easily be achieved.
However, it does refer to this Eric Meyer's article, which comes close to the effect you want to achieve.

By understanding how floats and the normal flow relate to each other, and understanding how clearing can be used to manipulate the normal flow around floats, authors can employ floats as a very powerful layout tool.
Because floats were not originally intended to be used for layout, some hacks may be necessary to make them behave as intended. This can involve floating elements that contain floats, "clearing" elements, or a combination of both.


Yet, Chadwick Meyer suggests in his answer a solution based on the :before CSS selector (variation of Leonard's answer).
It does work here.


Update Apr. 2021: Temani Afif suggests in his answer using Flexbox combined with a shape-outside.
But do check out the Backwards Compatibility of Flexbox, even though its support by all browsers is quite good.

KyleMit
  • 30,350
  • 66
  • 462
  • 664
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
17

Using flexbox combined with a shape-outside trick it's now possible with few lines of code.

.wrapper {
  display: flex; /* this is needed for the height:100% */
}

.box {
  text-align: justify;
  font-size: 20px;
}

.float {
  float: right; /* shape-outside only apply to float elements */
  height: 100%; /* take all the height */
  margin-left: 15px;
  /* push the image to the bottom */
  display: flex;
  align-items: flex-end;
  /**/
  shape-outside: inset(calc(100% - 100px) 0 0); /* make the text flow on the top free space*/
}
<div class="wrapper">
  <div class="box">
    <div class="float"><img src="https://picsum.photos/id/1069/100/100"></div>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam in dui quis orci ultricies aliquet nec sed enim. Mauris id rutrum nulla, et ornare leo. Donec aliquet malesuada tellus, eu laoreet lectus tincidunt ut. Quisque lacus magna, interdum eu urna
    ac, aliquet gravida orci. Pellentesque gravida urna sit amet nulla suscipit, at venenatis lorem dignissim. Morbi quis nunc eu velit condimentum ornare. Curabitur finibus tincidunt ullamcorper. Pellentesque tincidunt et odio vitae tempus. Praesent
    ac erat ut eros venenatis pulvinar. Pellentesque eu dapibus dui. Ut semper sed enim ut vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vitae elit eget velit porttitor consequat nec sed turpis. Proin libero nisl, egestas
    hendrerit vulputate et, lobortis non nulla. Aenean dui libero, dictum vel nibh eget, tristique egestas enim.
  </div>
</div>

Here is an article I wrote around this subject with more examples: https://css-tricks.com/float-an-element-to-the-bottom-corner/


Another version with less of code and without a wrapper for the image:

.wrapper {
  display: flex; /* this is needed for the height:100% */
}

.box {
  text-align: justify;
  font-size: 20px;
}

img {
  float: right; /* shape-outside only apply to float elements */
  height: 100%; /* take all the height */
  width: 100px;
  margin-left: 15px;
  /* push the image to the bottom */
  object-fit: contain;
  object-position: bottom;
  /**/
  shape-outside: inset(calc(100% - 100px) 0 0); /* make the text flow on the top free space*/
}
<div class="wrapper">
  <div class="box">
    <img src="https://picsum.photos/id/1069/100/100">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam in dui quis orci ultricies aliquet nec sed enim. Mauris id rutrum nulla, et ornare leo. Donec aliquet malesuada tellus, eu laoreet lectus tincidunt ut. Quisque lacus magna, interdum eu urna
    ac, aliquet gravida orci. Pellentesque gravida urna sit amet nulla suscipit, at venenatis lorem dignissim. Morbi quis nunc eu velit condimentum ornare. Curabitur finibus tincidunt ullamcorper. Pellentesque tincidunt et odio vitae tempus. Praesent
    ac erat ut eros venenatis pulvinar. Pellentesque eu dapibus dui. Ut semper sed enim ut vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vitae elit eget velit porttitor consequat nec sed turpis. Proin libero nisl, egestas
    hendrerit vulputate et, lobortis non nulla. Aenean dui libero, dictum vel nibh eget, tristique egestas enim.
  </div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Very sophisticated, best solution I found ever! – Sempervivum Sep 15 '22 at 03:08
  • Hi, see my version of this below! No `object-fit/position` or `shape-outside`, just a negative margin on an extra push down float instead. Though this flex-to-height solution is a genius one. – biziclop Oct 21 '22 at 05:56
17

Well... this is a pretty old post but I struggled and got away with this with a small workaround. I needed to have an image aligned to the right, and exactly 170px from the top. And need text to flow on top, left and bottom of image. So what I did is create a that is of 0px width, with 170px of height and float right. Then the img would float and clear right and voila!

<!-- I used CSS, but inline will serve well here -->
<div style="float: right; width: 0px; height: 170px"></div>
<div style="float: right; clear: right"><img src="..." /></div>
text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text

Worked pretty well :)

Chris Happy
  • 7,088
  • 2
  • 22
  • 49
Mauricio Morales
  • 988
  • 1
  • 9
  • 16
  • 1
    That's exactly what [VonC](http://stackoverflow.com/questions/499829/css-wrap-text-around-a-bottom-right-div/499883#499883) quoted: _It consists of floating a vertical "pusher" element (such as img, but it's probably smarter to just use an empty div), then floating the desired object under it, using the clear property._ – NGLN Aug 23 '11 at 22:48
  • This is the best solution if you actualy know the height of the external div! – Luca Sep 26 '15 at 13:23
  • This is old indeed, but just chiming in to say this works great! A neat solution indeed. Dare I say it should be the selected answer? – Shivam Sinha Oct 21 '19 at 20:55
  • This should be the accepted answer. very clear and concise. – Kingston Fortune Jun 11 '22 at 20:59
1

The simplest solution i found is to wrap img inside a div element and then use padding-top and margin-bottom values to align it.

This is my CSS

.contentDiv  .bottomRight img{
  height: 130px;
  float:right;
  padding-top: 60px;
  margin-bottom: -10px;
  }

and here is the HTML

<div class="contentDiv">
 <h1>If you are seeing this and reading it, then all is working well.</h1>
 <div class="bottomRight">
    <img class="bottomRight" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==">
 </div>
</div>

The reason padding and margin worked for me is because I use it inside the parent element "contentDiv" to auto adjust height of the div according to the content. Not sure if its of any use.

Popnoodles
  • 28,090
  • 2
  • 45
  • 53
1

If you have to support IE10-11, you can use @Temani Afif's solution with some modifications. Here is the important html and css

<div id="wrapper">
  <div class="box">
    <div class="push-float-img"></div>
    <img src="…" alt="">
    Long text…
  </div>
</div>
#wrapper {
  /* Flexbox gives explicit height used by #wrapper > .box */
  display: -webkit-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
}

/* For IE10 compatibility only */
#wrapper > .box {
  width: 100%;
}

/* If image width = 300% of its height */

#wrapper > .box > .push-float-img {
  float: right;
  width: 0;
  height: 100%;
  /* Image height in parent width percentages */
  margin-bottom: -20%;
}

#wrapper > .box > img {
  clear: right;
  float: right;
  margin-left: 10px;
  /* Image width in parent width percentages */
  width: 60%;
}

// "resize: horizontal" css is not supported by IE
if( !false || navigator.userAgent.match(/Trident\/7\./))
window.addEventListener('mousemove', function( ev ){
  var w = document.getElementById('wrapper');
  w.style.width = ev.clientX + 'px';
  //console.log( w );
});
* {  font: 16px sans-serif;  }

#wrapper {
  display: -webkit-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  /* make it resizable */
  resize: horizontal;
  overflow: hidden;
  /* demo styles */
  border: 1px solid blue;
  width: 1000px;
  max-width: 95vw;
  text-align: justify;
}

/* For IE10 compatibility only */
#wrapper .box {
  width: 100%;
}

#wrapper .push-float-img {
  float: right;
  width: 0;
  height: 100%;
  /* demo styles */
  background: #F8F;
  width: 10px;
}

#wrapper img {
  clear: right;
  float: right;
  margin-left: 10px;
  /* demo styles */
  opacity: .8;
  border-radius: 20px;
}

/* Change #wrapper.case-N  */

.case-1 .push-float-img { margin-bottom: -200px; }
.case-1             img {        height:  200px; }

.case-2 .push-float-img { margin-bottom: -100px; }
.case-2             img {         width:  300px; }

.case-3 .push-float-img { margin-bottom: -20%; }
.case-3             img {         width:  60%; }

/* NOPE! */
.case-4 .push-float-img { margin-bottom: -20%; }
.case-4             img {        height:  20%; }
<h1>Resize the below div!</h1>

<div id="wrapper" class="case-3">
  <div class="box">

    <div class="push-float-img"></div>

    <img src="https://picsum.photos/id/130/600/200" alt="">

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam in dui quis orci ultricies aliquet nec sed enim. Mauris id rutrum nulla, et ornare leo. Donec aliquet malesuada tellus, eu laoreet lectus tincidunt ut. Quisque lacus magna, interdum eu urna ac, aliquet gravida orci. Pellentesque gravida urna sit amet nulla suscipit, at venenatis lorem dignissim. Morbi quis nunc eu velit condimentum ornare. Curabitur finibus tincidunt ullamcorper. Pellentesque tincidunt et odio vitae tempus. Praesent ac erat ut eros venenatis pulvinar. Pellentesque eu dapibus dui. Ut semper sed enim ut vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vitae elit eget velit porttitor consequat nec sed turpis. Proin libero nisl, egestas hendrerit vulputate et, lobortis non nulla. Aenean dui libero, dictum vel nibh eget, tristique egestas enim.
  </div>
</div>
biziclop
  • 14,466
  • 3
  • 49
  • 65
0

For a jQuery solution, try the lowFloat plugin created by gilly3: https://github.com/gilly3/lowFloat

  • My lowFloat plugin is really mostly CSS and was inspired by [VonC's answer above](https://stackoverflow.com/a/499883/361684) where he quoted [Xapti's post in the webmaster world thread](https://www.webmasterworld.com/css/3528809.htm#msg3529991). I just implemented the part where you use JavaScript to make the pusher the correct size. I made it a jQuery plugin for convenience, but my original implementation was vanillaJS. See [my answer to a related question](https://stackoverflow.com/a/19820608/361684) where [lowFloat](https://github.com/gilly3/lowFloat) was born. – gilly3 Jul 25 '17 at 21:15
-1

Further to the solution posted, I've used a quick JQuery hack to dynamically adjust the height of the pusher, by taking the height of the area I wanted to bottom-right align away from the height of the content area, and applying it to the pusher div, as so:

$("#pusher").css("height", $("#content").height() - $("#contentToAlign").height() + 'px')

It needs a few slight tweaks, but generally works as well as you're going to get!

Spikeh
  • 3,540
  • 4
  • 24
  • 49
-3

The solution I found involves that you have a div whose width does not changes, nor does the amount of text. Then you can position the image inside the text and have it align=right. So if you have correct amount of text around it, then you you get the image on the right and at the bottom of the div.

    <style >
#contents{
    border: 2px solid red;
    background: #ddd;
    position: absolute;
    width:600px;
}



</style>
<div id="contents">
    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...    
    text text text text text text ...    text text text text text text ...   
    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...
    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...    
    text text text text text text ...    text text text text text text ...   
    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...
    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...    
    text text text text text text ...    text text text text text text ...   
    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...    text text text text text text ...
    text text text text text text ...    text text text text text text ...  <img src="http://daiphyer.com/images/daiphyerv6-sliced_02.png" ALIGN="RIGHT"/>
    text text text text text text ...    text text text text text text ...    text text text text text text ...    
    text text text text text text ...    text text text text text text ...   
    text text text text text text ...    text text text text text text ...   
    text text text text text text ...    text text text text text text ...    text text text text text text ...
     hey hey text text text text text text ...    text text text text text text ...    text text text text text text ...    
    text text text text text text ...    text text text text text text ...
</div>
user58670
  • 1,438
  • 17
  • 17
-4

Ok. So I've actually had this same problem and at some point the answer hit me like Saturday night cheese cake. It's almost the same hit and miss effect that you have when you try to set text wrapping in Word.

img.right {
     float: right;
}

Now all you have to do is just set it INSIDE the text where you want the lines to break. The text will float to the end of the text so it will always push the text to the left but if you put the image in the middle of the text like...

<p>This is some text <img src="example.jpg" class="right" /> and then add
some more text.</p>

the top part stays where it is and text is free to float above the image and the rest is pushed to the left of the image. It's a workaround but not nearly as tedious as using JS and if you use a WYSIWYG editor it's even easier. Come to think of it if you use a WYSIWYG editor it has that feature automatically. :P Problem solved.

Cheers.

NullDivision
  • 161
  • 1
  • 12