Reputation: 74935
I have a text container with paragraphs and headings. At the bottom of the page I want to float an image to the right of the page, while the text wraps around the image. The bottom of the image should be flush with the bottom of the last paragraph.
The page width is variable (responsive), but the image dimensions are fixed. Is it possible to accomplish this in HTML and CSS (CSS3 is fine)? If not, can it be done with a minimal amount of Javascript?
Here's a schematic example of what I want to accomplish:
The HTML currently looks something like this, but it can be changed if necessary. I don't particularly care where in the document the image is located. Using background images instead would be fine too.
<section>
<h2>...</h2>
<p>... ...</p>
<p>... ...</p>
...
<img src="...">
</section>
When I set float: right
on the image, it floats to the right but I cannot get it to align to the bottom of the page. Suggestions?
Edit: the closest I got is this... :-)
Upvotes: 53
Views: 36621
Reputation: 4837
Not quite there yet - but you might get where I'm going. Maybe someone else will complete this (if possible).
div.wrapper {
width: 300px;
transform: rotate(-90deg);
writing-mode: vertical-lr;
}
p.text {
margin-top: 1em;
writing-mode: vertical-lr;
}
img {
float: right;
transform: rotate(90deg);
height: 100px;
width: 100px;
}
<div class="wrapper">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAyCAYAAACqNX6+AAAAAXNSR0IArs4c6QAABCZJREFUeF7t3D9I80AUAPBXcFBwEQcRwcGl4KhLQTvXWQQHdRasWDroIEitxVVBRFCc/DO4ddRZhU5CwcWldCiVDiqFgkUEP9593HE5kjZNk/vTJouNudxd3u/eXYI2kWKx+AcAMDw8DENDQ/gx3CRH4Pv7GxqNBmk1Uq1W/wYHB6FWq5FfjI2NwcjIiOQu9WdzX19flrg3m83/IOPj4yQiYoEQJpiB4hTn9/d3KwhtPoSRC0FbcwQJYfwFcTvA24KEMN3BuIVwnSFidzptoLvLMfdsr3FynSEhjLvB4RXCc4aEMPYw3UL4BtLva4xfEL6D9BuM3xCBgfQ6TFAQgYP0GkzQENJATIeRBSEdxDQY2RDKQHSHUQWhHEQ3GNUQ2oCohtEFQjsQ2TC6QWgLEjSMrhDag/gNozuEMSDdwpgCYRxIpzCmQRgL0g7GVAjjQUSY399f8quBgQGj/43J818MaUBU/6QZEYIolnCamsIpSzKM24C7LSe5+22bM2bK8hpgr+e1jVxABbQH8SugftUTkAOrVluQoAIYVL1+QWkHIitgstrpFEobEFUBUtWuE5RyEF0Coks/lIHoEgBxpKrul3QQ1Rfsdk5X1U9pIKou0C2AUznZ/Q4cRPYFdQugGiYwEB0h8Juu6XQa1tbWYG5ujsX+9vYWVldXyf7NzQ2srKywY29vb7C8vAzFYhHW19chk8lAvV4nx52+HEvbOT8/Z/UcHBzA3t4e2RfrPD4+Zt9+9h1ERwgMAh+kp6cnBoLB2dragpOTExIs+jkajbJz4vE4LC4uEkz8jGCtrvPj4wM2Nzdhf38fsB5+o/2wqxPL+QaiKwQ/ImOxGJTLZTJSaYZgdjw+PgIdpblcDqampkjQeSwM7PPzM1xfX7OyWLfddeN5iHF6egqjo6MWkHZ1dg2iMwSNRKVSIR/xpQgYaB4EAXCj0wm/jwC4j2gYWH7/7OyM7NNj9/f3JIOOjo4gEolAPp+3wNG+tKoT2/AMYgKEuEDjVGIHQjMCy2OAS6USARIzQhz5FG9jY4PVOz09DZeXl7Czs8OaTyQSFlQ+y8Q6OwYxEYJGxm8QWt/DwwPwizZCIWoqlQJ8Q8bV1RV8fn6SjHl5ebFMe55BTIZoB+JlyqJrA2YUjng6dYlZiXErFApweHhIQH5+fhynQVdTVi9AtALhpygsJy7q/OJsN4XhXRlu8/PzbB0SUTALdnd3YXt7m9wE4JR2cXHB1iV+CuurV2vYTVleb3v529eFhQW2hszMzFhuj2m5iYkJAoYBx8V/dnaWPPtks1l2K21729tLGeFmUacLudsHQ5x2cMOg4kZvlzF7kskk3N3dweTkJDlOHwzxgZJ/+MNBsLS0BK+vr+ShE4/Rl/+wDAlfzyTyydkXE4C8nil8gZmc4LdqhX+B2T8GuESS5P5SHQAAAABJRU5ErkJggg==" />
<p class="text">
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>
</div>
Upvotes: 0
Reputation: 272723
A CSS only and responsive solution that works without complex code. Resize the browser and see the magic in play:
.wrapper {
display: flex;
border: 1px solid;
}
.box {
text-align: justify;
font-size: 20px;
}
.float {
float: right;
height: 100%;
margin-left: 15px;
display: flex;
align-items: flex-end;
shape-outside: inset(calc(100% - 100px) 0 0);
}
<div class="wrapper">
<div class="box">
<div class="float"><img src="https://picsum.photos/id/1/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>
More details: https://css-tricks.com/float-an-element-to-the-bottom-corner/
PS: I am the author of the above article
Upvotes: 3
Reputation: 3523
A responsive solution for 2020, inspired by @gilly3's solution, and until CSS Exclusions arrive.
:before
element instead of spacer div
calc()
.container {
display: flex;
}
img {
float: right;
clear: right;
margin: 20px 0 0 20px;
height: 30vw;
@media (min-width: 1200px) {
height: 400px;
}
}
.container-inner:before {
content: "";
float: right;
height: calc(100% - 30vw - 20px);
@media (min-width: 1200px) {
height: calc(100% - 400px - 20px);
}
}
<div class="container">
<div class="container-inner">
<img src="https://picsum.photos/200" />
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Doloribus ab, doloremque quasi, obcaecati aspernatur nam possimus harum architecto odit molestiae pariatur aliquid necessitatibus, corrupti mollitia provident quis quam eligendi qui.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Doloribus ab, doloremque quasi, obcaecati aspernatur nam possimus harum architecto odit molestiae pariatur aliquid necessitatibus, corrupti mollitia provident quis quam eligendi qui.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Doloribus ab, doloremque quasi, obcaecati aspernatur nam possimus harum architecto odit molestiae pariatur aliquid necessitatibus, corrupti mollitia provident quis quam eligendi qui.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Doloribus ab, doloremque quasi, obcaecati aspernatur nam possimus harum architecto odit molestiae pariatur aliquid necessitatibus, corrupti mollitia provident quis quam eligendi qui.</p>
</div>
</div>
Upvotes: 1
Reputation: 91467
Create a spacer element with float: right
and height
equal to the height of the content minus the height of the image. Then use float: right
and clear: right
on the image:
<div class="spacer"></div>
<img class="bottomRight" src="" />
<div class="content"></div>
.spacer {
height: calc(100% - 200px);
width: 0px;
float: right;
}
.bottomRight {
height: 200px;
float: right;
clear: right;
}
My demo uses fixed dimensions in the container element. Since that is rarely a realistic case, it probably makes more sense to use JavaScript to size the spacer. Call this function, passing a reference to the spacer element when the document is ready and during the window.onresize
event.
function sizeSpacer(spacer) {
spacer.style.height = 0;
var container = spacer.parentNode;
var img = spacer.nextElementSibling || spacer.nextSibling;
var lastContentNode = container.children[container.children.length - 1];
var h = Math.max(0, container.clientHeight - img.clientHeight);
spacer.style.height = h + "px";
while (h > 0 && img.getBoundingClientRect().bottom > lastContentNode.getBoundingClientRect().bottom) {
spacer.style.height = --h + "px";
}
if (lastContentNode.getBoundingClientRect().bottom > img.getBoundingClientRect().bottom) {
spacer.style.height = ++h + "px";
}
}
This function works (see the demo), and can be reworked for jQuery or your library of choice. It's not meant to be plug-in quality code, but serves to illustrate the concept.
Edit: I created a jQuery plugin version (github | jsFiddle demo) that supports floating bottom left or bottom right. It also supports specifying which element to align the bottom with.
By the way, I didn't bother trying to support IE7.
Upvotes: 59
Reputation: 12650
CSS only Solution.
Using media queries one can accomplish this layout.
HTML
<section>
<h2>...</h2>
<p>... ...</p>
<p>... ...</p>
<img src="..." class="show-medium">
...
<img src="..." class="show-small">
</section>
CSS
html, body {
height: 100%;
width: 100%;
}
img {
display: none;
float: right;
clear: right;
}
@media (max-width: Xpx), (max-height: Xpx) {
/* show img for small screens */
.show-small { display:block; }
}
@media (min-width: Xpx) and (max-width: Xpx) and (min-height:Xpx) and (max-height: Xpx) {
/* show img for medium screens */
.show-medium { display:block; }
}
@media (min-width: Xpx) and (min-height: Xpx) {
/* show img as body background for large screens */
body {
background: url("http://placehold.it/200x300") no-repeat fixed right bottom transparent;
}
}
It plays well at different screen resolutions. See demo.
One has to play/adjust the CSS media queries as well as the position of the images within the markup in order to make it work.
CSS media queries is supported in Firefox 3.5+, Opera 7+, Safari 3+, Chrome and IE9+. For older IE versions one can use this fix: http://code.google.com/p/css3-mediaqueries-js/
Upvotes: 1
Reputation: 125443
I think the future way how to tackle this problem will be with CSS Exclusions.
CSS Exclusions extend the notion of content wrapping previously limited to floats. ... Elements layout their inline content in their content area and wrap around the exclusion areas in their associated wrapping context (--excerpts from the spec)
This msdn article also explains exclusions
...web authors can now wrap text so that it completely surrounds elements, thereby avoiding the traditional limitations of floats. Instead of limiting elements to floating either to the left or right relative to their position in the document flow, CSS Exclusions can be positioned at a specified distance from the top, bottom, left, or right sides of a containing block, while remaining part of the document flow.
Ironically, to date this only works in IE10 (look for wrap-flow:both here)
This is what the code looks like:
<div class="container">
<div class="exclusion">
Exclusion positioned at bottom right hand side of text.
</div>
<div class="dummy_text">
<p>text here</p>
</div>
</div>
.container {
font-size: small;
background: aqua;
position: relative;
}
.exclusion {
-ms-wrap-flow: both;
-ms-wrap-margin: 10px;
z-index: 1;
position:absolute;
right:0;
bottom:0; /* try fiddling with this. For some reason bottom: -10px (or the like) works better here */
width: 150px;
height: 100px;
background: url(http://placehold.it/150x100) no-repeat;
}
So as you can see - even though the exclusion is positioned absolutely - it still acts like a float - in this case: float bottom right.
Regarding browser support:
Check out this site which shows which properties are supported by the browsers (to date: only IE10+ supports wrap-flow:both
)
PS: Latest updates concerning CSS exclusions (and other simlar modules like CSS regions and CSS Shapes) can be found at the Adobe Web Platform Team Blog
Upvotes: 7
Reputation: 4609
With a little bit of JavaScript and CSS I did it like this:
http://jsfiddle.net/stichoza/aSScx/
One simple floatify()
function.
Idea inspired by: http://www.csstextwrap.com/
Upvotes: 2
Reputation: 61055
Here's a lightweight solution with a bit of jQuery:
http://jsfiddle.net/isherwood/6BvC2/
<section class="flagpole">
<div class="pole"></div>
<img class="flag" src="..." />
<p>Paragraphs...</p>
</section>
.pole, .flag {
float: right;
clear: right;
}
.pole {
width: 0.1px
}
function setFlag() {
$('section.flagpole').each(function () {
var poleHeight = $(this).height() - $(this).find('.flag').height();
$(this).find('.pole').height(poleHeight);
});
}
setFlag();
$(window).on('resize', function () {
setFlag();
});
To dispel any concerns about plagiarism, this solution is based on another similar answer I provided a while back.
Upvotes: 0
Reputation: 16157
Possible CSS Solution: (only tested in chrome)
It looks like this might work using CSS3's flex box properties and a combination of background-image
properties. I was able to get it pretty close using only CSS. (It works but needs a little tweaking) Also, this may not be ideal cause I did have to change the markup a little bit to make this work. But its probably worth a shot if you are looking for a pure CSS solution.
Here is a Demo -> http://jsfiddle.net/ADSH2/
New Markup: (not to much different)
<section >
<h2>Some Heading:</h2>
<p>...</p>
<p class="last">
<span class="image"></span>
</p>
</section>
CSS:
.last {
display:inline-flex;
flex-direction:row;
}
.image {
padding:5px 0 0 5px;
width:100%;
background-image:url("http://dribbble.s3.amazonaws.com/users/200359/screenshots/758731/stackoverflow_logo.png");
background-size:100%;
background-repeat:no-repeat;
background-position:bottom right;
}
Resources:
Upvotes: 3
Reputation: 54
use this :
<section class="post">
<h2>...</h2>
<p>... ...</p>
<p>... ...</p>
...
<img src="...">
</section>
<style>
.post img {float:right;margin-top:80%}
</style>
change 80% to get best result.
Good Luck.
Upvotes: 0
Reputation: 66103
I have worked on a jQuery-based solution — probably not as elegant as the one posted by gilly3 though ;) and it's also slower and a bit bloated...
My trick is to append two <div>
s to the section, which is floated to the left and hidden width a width of 0. One of the div, a designated ghost element that will have the same dimension as the image, will be positioned below another div that is the designated height spacer. The script uses a while loop to establish if the ghost element has reached the bottom of the parent section element. If this has not happened, it will increment the height of the height spacer by 1, until the condition is satisfied.
The markup I have used is as follow. I'm using the HTML5 attribute data-bottom-image
to identify sections that you have the image to be floated to the bottom. Of course it is dispensable, depending on how you want to select for the correct section element.
<section id="c1" data-bottom-image>
<h2>...</h2>
<p>...</p>
<img src="http://placehold.it/250x100" />
</section>
And the jQuery script:
$(function () {
$("section > img:last-child").each(function () {
// Offset image based on the bottom and right padding of parent
var $par = $(this).parent();
$(this).css({
bottom: $par.css('padding-bottom'),
right: $par.css('padding-right')
});
});
// Function: adjust height of height-spacer, pixel by pixel
function adjustHeightSpacer($par, $hs, $is) {
// Stretch height spacer
$hs.height(0);
$hs.css({
height: $par.find("img").position().top - parseInt($par.css('padding-top'))
});
// Adjust height spacer
while($par.height() - $is.height() > $is.position().top - parseInt($par.css('padding-top'))) {
$hs.height("+=1");
}
while($par.height() - $is.height() < $is.position().top - parseInt($par.css('padding-top'))) {
$hs.height("-=1");
}
};
$("section[data-bottom-image]").each(function() {
// Append two spacers:
$(this).prepend('<div class="ghost height-spacer" /><div class="ghost image-spacer" />')
var $hs = $(this).find(".height-spacer"),
$is = $(this).find(".image-spacer");
// Adjust image spacer dimension
$is.css({
height: $(this).find("img").height(),
width: $(this).find("img").width()
});
// Adjust height spacer
adjustHeightSpacer($(this), $hs, $is);
});
$(window).resize($.debounce(250,function() {
$("section[data-bottom-image]").each(function() {
// Adjust height spacer
adjustHeightSpacer($(this), $(this).find(".height-spacer"), $(this).find(".image-spacer"));
});
}));
});
And here is the working Fiddle: http://jsfiddle.net/teddyrised/xmkAP/5/
Upvotes: 2