Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Floating elements to bottom

My problem is very specific, and will haunt any web developer from the moment he/she will read it. So be carefull!

I've got a layout planned for a website I'm building. The idea is that there is are tilted <hr/> elements on the page, which the text will wrap around to (see image below. The black line represents the <hr/>)

the way it should be

What you see are some orange stripes. Each and every one of these are a floating element with widths of 10px, then 20px, then 30px etc. The black line represents where they stop, and thus where they cut off the text.

The big orange area is, as you may guess, a floating element with a width of 0 and a height of 100% of it's parent minus the height of the 70 other floating elements (the stripes), which is 70px.

The issue: this doesn't seem to be possible. What I get is this:

what actually happens

Since these little stripes are each 1px high, they will show up, no matter what. But the big one relies on the height of its parents. If I was to fix the parent's height, it would work. But I want the box to be dynamic. This means I should be able to change the text inside. Also, if I were to fix it's height, scaling the page up and down looks disastrous.

What I need to happen is this: The first, big floating element should be taking up the space it needs (100% - 70px), without giving it's parent a fixed height, while keeping it floated.

I am going to reward the person solving this with all the reputation I can put in, since this has been pestering me for months.

For people trying to solve the issue. There are some thoughts that may help:

  1. Table cells can align elements to it's bottom
  2. I've tried rotating in a lot of ways. Too bad there's no upside down text.
  3. I've tried adding margins, paddings and borders to the first floating div. Not one combination has worked so far.
  4. I don't actually want the elements to float. This is just the way I chose to try, because I don't know another way to wrap text around an element. You are free to try ANYTHING you want, as long as the text inside can be changed, and it looks as good when scaled up or down, as it does normally.
  5. I think the only solution is to use Javascript to calculate what height the div would need.

Here is all the code packed into a Fiddle

EDIT: I think I do know the solution. I just don't know how to program it.

With Javascript, the browser should calculate the height of the content (text, images, their margins, etc.) inside the container. Then, #lw should change to that height. After that has happened, #lw should be shrunk down by 1px. After that has happened, a check should be made to see whether the content changed in height. If this has happened, the browser should check if the height of the content's height is bigger than the height of #lw + 70px. If it did not get higher than that, the process should repeat. If it did, #lw should be scaled down by 1px again, and the process should stop. When resizing the window, the process should start from the beginning.

This seems like one hell of a job, and I would gratefully take on the challange if I were to know JS. I guess I'm off to Codecadamy.

EDIT:

In the meantime, I have come up with a less complex version of this problem. I have looked into css-shapes, and found out that these will allow me to do what the 70 floating elements did, with one element. I have made another set of files, BUT There is a js file needed for it to work. What I'll do here is paste the HTML and CSS as code, and link to the js code.

Just like the older version, the code should measure what the optimal height is. In my code, I have added a <script> tag with an exact description of what should happen.

I think I start to look lazy, since I can't give any input regarding actual Javascript code.

HTML

<!doctype html>
    <html>
        <head>
            <meta charset="utf-8">
            <link rel="stylesheet" type="text/css" href="css/stylesheet.css">
            <script src='js/shapes.polyfill.min.js'></script>
        </head>
        <body>
            <div id="container">
                <div id="polybreak"></div>
                <p>
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim arcu, porttitor vitae hendrerit euismod, efficitur pretium nulla. Sed a justo nulla. Aenean vel erat purus. In velit arcu, lacinia in justo in, vestibulum pellentesque mauris. Phasellus quis eros nunc. Vivamus fringilla euismod est, eget consectetur lacus cursus et. Fusce at arcu ac turpis laoreet feugiat nec a nulla.
                </p>
                <p>
                    Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Quisque vehicula mollis leo non tempus. Praesent scelerisque dui felis. Suspendisse tristique, sapien egestas semper cursus, elit quam facilisis sapien, sit amet ornare odio nibh sed nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum libero nisi, efficitur id felis non, maximus ultricies sapien. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce rhoncus nibh enim, eget dignissim neque placerat et. Nam sit amet placerat sapien. Quisque vitae risus ac dolor porttitor tincidunt.
                </p>
                <p>
                    Nullam volutpat, lorem vitae ultricies lobortis, ligula ligula posuere erat, sed gravida sapien nisi non ante. Aliquam tellus sapien, placerat mollis tempor quis, consequat imperdiet magna. Etiam cursus ornare mauris sit amet varius. Sed dignissim euismod felis, at aliquet est fringilla at. Duis lorem nunc, imperdiet nec rhoncus et, egestas quis nunc. Nulla imperdiet elementum libero consequat tempor. Donec ante nunc, pellentesque nec ex dapibus, auctor sagittis ipsum. Phasellus ut est ex.
                </p>
            </div>
            <script src='js/shapes.polyfill.min.js'></script>
            <script type="text/javascript">
                On load and on resize:
                Make #polybreak the same height as #container + 60px.

                Subtract 1px off #polybreak''s height and check: is #container higher than #polybreak? If so, add 1px and stop. If not, repeat.
            </script>
        </body>
    </html>

CSS

html, body{
    margin: 0;
    padding: 0;
    height: 100%;
}

p{
    text-align: justify;
}

#container{
    width: 700px;
    margin: 0 auto;
}

#polybreak{
    width: 100%;
    float: left;
    shape-outside: polygon(0 calc(100% - 100px), 700px calc(100% - 1px), 700px 100%, 0 calc(100% - 99px));
}

Link to the raw js code https://raw.githubusercontent.com/adobe-webplatform/css-shapes-polyfill/master/shapes-polyfill.min.js

like image 544
Gust van de Wal Avatar asked Sep 14 '14 20:09

Gust van de Wal


2 Answers

As everybody is posting Javascript answers either way, let's throw in an actual solution into the bunch. The problem even using Javascript is that there is no defined way to 'calculate' the final height of #lw as predicting the behaviour of the text wrapping is impossible.

//Get a nice starting point
Zepto(".lW").hide();
var sh = document.getElementById("wrapper").scrollHeight;
document.getElementById("lw").style["height"] = sh - 60 + "px";
Zepto(".lW").show();

//Start the search
var height = parseInt(document.getElementById("lw").style["height"]);
var difference = Infinity;
var bestheight = 0;
var i = 0;
var checker = setInterval(function(){
    i++;
    height += 1;
    document.getElementById("lw").style["height"] = height + "px";
    var sh = document.getElementById("wrapper").scrollHeight;

    //Now the interesting part, we don't want to get the first situation
    // where the #lw is greater than the floats, what we want is the most
    // optimal part, which we are going to search over a certain pixel range.
    // In this case that pixel range is hardcoded as 30 pixels.
    if(Math.abs(height + 70 - parseInt(sh)) < difference){
        difference = Math.abs(height + 70 - parseInt(sh));
        bestheight = height;
    }
    if(i>30){
        clearInterval(checker);
        document.getElementById("lw").style["height"] = bestheight + "px";
    }
},0);

Here is JSFiddle of the solution.

enter image description here

like image 74
David Mulder Avatar answered Sep 22 '22 12:09

David Mulder


Modern CSS has a special module for such tasks: CSS Shapes. There is a polyfill for it created by Adobe. Maybe it helps?

like image 35
Ilya Streltsyn Avatar answered Sep 22 '22 12:09

Ilya Streltsyn