10

This is for a very simple bar graph I'm working on,

<div id="container">
  <div style="display:inline-block;">
  </div>
  <div style="display:inline-block;">
  </div>
  <div style="display:inline-block;">
  </div>
</div>

If I set the container to relative and the inner divs to absolute & bottom:0, then they all overlap. They flow nicely without the absolute positioning but then the bar graph is upside down.

Note: My intention was to retain the inline flow of the bars and not have to explicitly specify the horizontal positions.

Here is a better example of the problem.

http://jsfiddle.net/benstenson/NvvV6/1/

1) correct orientation but vertical alignment is top
<div id="no-content" class="container">
    <div class="a"></div>
    <div class="b"></div>
    <div class="c"></div>
</div>

2) wrong orientation, vertical alignment top
<div id="has-content" class="container">
    <div class="a">a</div>
    <div class="b">b</div>
    <div class="c">c</div>
</div>

3) mixed orientation, alignment is crazy
<div id="mixed" class="container">
    <div class="a">a</div>
    <div class="b">b</div>
    <div class="c"></div>
</div>

4) correct orientation and correct alignment but<br/>
flow has been lost and horizontal position must be explicit
<div id="absolute" class="container">
    <div class="a">a</div>
    <div class="b">b</div>
    <div class="c"></div>
</div>

5) here we go!
<table class="container">
    <tr>
        <td><div class="a">a</div></td>
        <td><div class="b">b</div></td>
        <td><div class="c"></div></td>
    </tr>
</table>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

css

body {padding:1em;font-family:sans-serif;font-size:small;}
.container {
    height:2.5em;width:50%;margin-bottom:1em;
    background-color:lightgray;
    font-size:larger;
    font-weight:bold;
    text-transform:Uppercase;
}
div.container > div {
    width:32%;
    display:inline-block;
    background-color:black;
    color:cyan;
}

#absolute { position:relative;}
#absolute > div {position:absolute;bottom:0px;opacity:.3;}

.a {height:50%;}
.b {height:60%}
.c {height:80%;}

td{width:33.333%;vertical-align:bottom;}
td > div{​background-color:black;​color:cyan;}​

So is there a better way to do this, like with the webkit flexbox or something?

Benjamin
  • 3,134
  • 6
  • 36
  • 57
  • Try giving them relative positioning. – Jared Jun 17 '12 at 03:58
  • @Jrod the terminology for relative vs absolute is confusing to me in css. I tried it both ways just to be sure. It is still upside down. – Benjamin Jun 17 '12 at 04:00
  • Can you show an example of what you're fighting vs what you want? – jcolebrand Jun 17 '12 at 04:01
  • I'm a bit confused by what you currently have and what you're trying to get. Are the child div elements the bars in the graph? Could you elaborate a bit please? This seems to look aligned for me...http://jsfiddle.net/ZjMp5/ – Zhihao Jun 17 '12 at 04:03
  • @ZhihaoJia thank you for the example. Maybe my css reset is messing it up. I will have to experiment some more. – Benjamin Jun 17 '12 at 04:11
  • @jcolebrand I added more explanation. It seems like there should be a more simple way than using a table (for vertical-align). – Benjamin Jun 19 '12 at 00:03
  • @Jrod The thing that I was trying to do was avoid specifying `left:_px` for the bars. – Benjamin Jun 19 '12 at 00:04
  • @ZhihaoJia it kind of works but of course the flow is top to bottom. Also notice how adding content seems to anchor the element to the top. – Benjamin Jun 19 '12 at 00:06
  • Ok! Now that's a problem that can be solved. I need a few minutes to work on it, but someone else is likely to come along before me. – jcolebrand Jun 19 '12 at 00:08
  • 1
    http://stackoverflow.com/questions/6116423/how-to-vertically-align-floating-divs-to-the-bottom – jcolebrand Jun 19 '12 at 00:09
  • @jcolebrand that is a really cool example. I had thought `display:table-cell` required containers with `table-row` and `table`. So I could not understand why anyone would want to ever use it. But if it does not require the containers then that is great. However, I realized that the flowing thing will not be accurate enough with percentage widths. In order to keep from using pixels I have to use a table or maybe flexbox or something. I will probably go with the divs nested in a table until I experiment with it more. – Benjamin Jun 19 '12 at 00:17
  • I just linked that till I had a bit more time to explore. Keep playing though and see what you can come up with, but that looks like it's what you want, if narrow. Yes? I also considered if you could do a height calculation and force a margin-top or top+position:relative or something? – jcolebrand Jun 19 '12 at 00:18
  • @jcolebrand Actually I think it just looks like it is bottom aligned because the container is no higher than the tallest bar. http://jsfiddle.net/benstenson/7BBqC/18/ I really think tables is the html/css way to do it. Flex box would be the pure css way to do it. – Benjamin Jun 19 '12 at 00:34
  • @jcolebrand check it out http://jsfiddle.net/benstenson/m6vR7/1/ does this work on your browser? – Benjamin Jun 19 '12 at 01:07

3 Answers3

2

Works for me when absolutely positioned:

<style type='text/css'>
#container{
 position  :relative;
 border    :1px solid #000;
 height    :60px;
 width     :100px;
}
 .b{
   position:absolute;
   width   :20px;
   bottom  :0
  }
 .b1{background:blue  ;height:10px; left:0px}
 .b2{background:red   ;height:30px; left:30px;}
 .b3{background:yellow;height:50px; left:60px}
</style>

<div id="container">
  <div class='b b1'></div>
  <div class='b b2'></div>
  <div class='b b3'></div>
</div>​​​​​​​​​​​​

Fiddle here.

Daniel Szabo
  • 7,181
  • 6
  • 48
  • 65
  • 1
    I could have done this but I was trying to keep the flow in order to avoid using `left:_px`. I wonder if you need to use either tables or flexbox for this. I stay far away from pixels whenever possible. – Benjamin Jun 19 '12 at 00:09
  • This actually seems to be how stackoverflow does the rep bar graph in the user profile view. – Benjamin Jun 19 '12 at 03:26
  • @Benjamin: I agree with your philosophy, but you can literally spend weeks trying to do sh*t like this in a "best practice" sort of way -- especially when your graphs start to get more complicated or you start to add more features. Don't forget that DOM elements aren't really meant for "charts" or "graphs"...which means you can afford to color outside the lines a bit when it comes to using them for creative things beyond semantic page layout. – Daniel Szabo Jun 19 '12 at 05:36
  • @Benjamin: Plus, and this might just be me, I've found that Absolute positioning with :px is usually the fastest way to achieve cross-browser-compatible results in a headache-free fashion (outside of using .js charting libs). Maintaining charting apps designed with absolute position is also easier because of the intuitiveness of the x/y coordinate system that absolute positioning is based on. I'm sure you'll find a million people that scream "that's wrong! its not semantic!". To them I would argue that it works, it gets results, and I'm able to move on to the next project task more quickly. – Daniel Szabo Jun 19 '12 at 05:43
  • I appreciate the advice. I never heard that charts were outside of the scope of DOM elements. That would leave only image maps or plugins for interactive data visualization? Seems like an unfortunate design. I agree that sometimes the philosophically perfect method can be a waste of time. But I would rather know the correct way to do something and then have the option of taking a deliberate shortcut instead of just doing it for a lack of knowing any other way. – Benjamin Jun 19 '12 at 17:03
  • I also read that css pixels are poorly defined and therefore are typically implemented relative to inches (1/96in) rather than being actual pixels on the screen. If that is the case then I would probably go with inches just as soon as pixels. – Benjamin Jun 19 '12 at 17:17
  • @Benjamin: Image maps were the de-facto for a while -- big vendors like Telerik invested heavily in charts apps that created images server side and pushed it down to the browser. However, now that has arrived and is almost universally supported, I would recommend checking it out for charts. Also, I'd highly recommend the raphael.js charting library. (raphaeljs.com). It uses SVG graphics, but its super easy to work with and makes some awesome looking charts. – Daniel Szabo Jun 19 '12 at 17:47
2

this is working on my browser (Chrome 19)

enter image description here

html

<div id="container">
    <div id="a">a</div>
    <div id="b">b</div>
    <div id="c">c</div>
</div>

css

#container {
    height:10em;
    width:90%;
    border:1px solid black;

    display:-moz-box; /* Firefox */
    display:-webkit-box; /* Safari and Chrome */
    display:box;

    -webkit-box-align:end;
}

#container > div {
    width:34%;
    border:1px solid red;

    -moz-box-flex:1.0; /* Firefox */
    -webkit-box-flex:1.0; /* Safari and Chrome */
    box-flex:1.0;
}

#a {height:20%}
#b {height:50%}
#b {height:70%}

http://jsfiddle.net/benstenson/m6vR7/

Benjamin
  • 3,134
  • 6
  • 36
  • 57
1

Here is another approach. It takes an extra wrapper around each bar. The idea is to make several columns .bar-container that span the correct width of the bars and the entire height of the #graph.

<!DOCTYPE html>
<html>
    <head>
        <title>Testing</title>
        <style type="text/css">
            .bar-container{
                float:left;
                height:100%;
                margin-right:10px;
                position:relative;
                width:30%;
            }
            .bar {
                border:1px solid black;
                bottom:0;
                position:absolute;
                width:98%;
            }

            .bar-1 {
                height:50px;
            }

            .bar-2 {
                height:100px;
            }

            .bar-3 {
                height:75px;
            }

            #graph {
                height:500px;
                margin:20px auto;
                position:relative;
                width:500px;
            }
        </style>
    </head>
    <body>
        <div id="graph">
            <div class="bar-container">
                <div class="bar bar-1">
                </div>
            </div>
            <div class="bar-container">
                <div class="bar bar-2">
                </div>
            </div>
            <div class="bar-container">
                <div class="bar bar-3">
                </div>
            </div>
        </div>      
    </body>
</html>
Jared
  • 12,406
  • 1
  • 35
  • 39