Is it acceptable to post a HTML/CSS file that others may find useful?

This is what is wrong with that approach :smile:

 <li><a href="/experts/">Expert<br>Advice</a></li> 

Just add that line in your code and see what happens.

Now do the same with my example:

<a href="/experts/">Expert<br>Advice</a>

I knew there would be something :stuck_out_tongue:

With my example, changing the anchors to display: inline-block;, width: 100%; and height: 100%; enables them to fill the list element, which looks a bit better, but the text is aligned to the top rather than nicely in the middle.

That still won’t work as you can’t base 100% height on a table-cell. It works in chrome (when it shouldn’t) but won’t work in Firefox or IE.

There is a fix and you would need to set the display:table element to height:1px and then set the list item display:table-cell to height:100% and then you will get the full height in IE and Firefox as well.

Of course you lose the vertical alignment and to achieve that you would need to nest another element inside the anchor and set that to display:table-cell and the anchor to display;table.

Which is why I prefer my minimalist version :slight_smile:

It is 2015, why isn’t CSS more flexible and intuitive? So people don’t have to do dirty tricks?

1 Like

CSS is now more flexible and intuitive than it has ever been - provided that you ignore old browsers. It is because people insist on using antiquated browsers that are six or more years old (two or three lifetimes ago in web terms) that there are these issues.

I agree, especially with flexbox, but its still not great. Say I want a child element to scale according to a parent element, why can’t isn’t this kind of flexibility available?:

.childElement1 {
      width: 60%h; /* 60% of the height of the parent element*/
      height: 20%w + 30px; /* 20% of the width plus 30 pixels */
}

And why can’t I tell an element to just fill it’s parent?

Just a couple of simple examples.

Can’t calc() do some of those things?

This seems to do the job using an unordered list in the nav. It is almost the same as before but has a little bit of javascript to do what css can’t. I think it is ok considering CSS can’t do it and if javascript is off, the menu is still perfectly usable, but just looks a little odd.

PaulOB’s example is more elegant but if you think an unordered list should be used with anchors in a nav block, then this should be of help. (Only tested in Chrome and Firefox, but uses simple code).

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style>
.bigBox{
    border:1px solid red;
    padding:10px;
}
.nav ul {
    display:table;
    border-collapse:collapse;
    width:75%;
    margin:auto;    
}
.nav li {
    position: relative;
    display: table-cell;
    vertical-align: middle;
    text-align:center;
    border:1px solid #666;
    padding: 0;
    margin:0;
    background-color: green;
}
.nav a {
    background:red;
    display: block;
    color:#fff;
    padding-top: 5px;
    padding-bottom: 5px;
    padding-left: 2px;
    padding-right: 2px;
    text-decoration:none;
    vertical-align: middle;
    margin: 0;
}
.nav a:hover{background:blue}
@media screen and (max-width:500px){
    .nav li{display:block;}
}

</style>
</head>

<body>
<div class="bigBox">
        <nav class="nav">
            <ul>
                <li><a href="/index.html"><span>Home</span></a></li>
                <li><a href="/features/">Features</a></li>
                <li><a href="/experts/">Experts</a></li>
                <li><a href="/quiz/">Quiz</a></li>
                <li><a href="/projects/">Projects</a></li>
                <li><a href="/horoscopes/">Horoscopes bla bla bla</a></li>
            </ul>
        </nav>
</div>
<script>
    var navAnchors = document.getElementsByTagName("nav")[0].getElementsByTagName("a");
    var startPad = []; // store original values

    // grows anchor hight to fit a tables cell height
    function growAnchors() {
        // restore original values if they have been established
        for (var i=0, il=navAnchors.length; i<il; i+=1) {
            if (!!startPad[i]) {
                navAnchors[i].style.paddingTop = startPad[i][0];
                navAnchors[i].style.paddingBottom = startPad[i][1];
            }
        }
        // determine optimal padding
        var rowHeight = navAnchors[0].parentNode.clientHeight;
        for (var i=0, il=navAnchors.length; i<il; i+=1) {
            var navAnchor = navAnchors[i];
            var pad = 0;
            // make sure we establish original padding
            if (!startPad[i]) {
                navAnchor.style.paddingTop = pad + "px";
                navAnchor.style.paddingBottom = pad + "px";
            }
            // work out optimal padding
            while (rowHeight > navAnchor.clientHeight && pad < 500) {
                pad += 1;
                navAnchor.style.paddingTop = pad + "px";

                // cater for an odd height
                if (rowHeight > navAnchor.clientHeight) {
                    navAnchor.style.paddingBottom = pad + "px";
                }
            }
            // record original optimal padding
            if (!startPad[i]) {
                startPad[i] = [navAnchor.style.paddingTop, navAnchor.style.paddingBottom];
            }
        }
    }

    growAnchors();

   window.onresize = function() {
    growAnchors();
   }

</script>
</body>
</html>

As far as I am aware, you can’t use calc() to choose to use a percentage of the height or width, but you can add 30px for example.

IMO you should be able to scale something as a percentage of:

  • the width of the parent
  • the height of the parent
  • the smallest of the width and height of the parent
  • the largest of the width and height of the parent
  • all of the above but based on another specific element that is not the parent
  • all of the above but based on the viewport size

Yes you can use calc() with percentages.
e.g.

width: calc(100% - 3em);

You can use it for height also but the height must be based on a parent that has height defined and not auto or content height. If the parent has a percentage height then that parent’s parent must also have a height defined and so on all the way back up the tree.

Yes that’s always possible.

That’s only possible when you follow the rules I set out in the first reply to calc().

Height is one of the most misunderstood properties and I have been giving this answer since about 2002 as everybody always asks the question at some stage.:slight_smile:

If you give an element a height then that element is fixed in height. It’s content can never grow beyond the height you set.

So imagine that height worked as you expected and you give a child 100% height (even though its parents height is not defined). You now have a circular reference (which CSS hates) as the height of the inner element is dependent on the height of the parent which will only have a height once the inner element is in place and holds content. The effect would be that your child’s height would be zero because the parents height is zero until you place content inside. It’s a circular reference that can’t be resolved for that case. It makes no sense anyway as there would be no need for the height unless you were trying to match the height of some other unrelated element.

Now if your parent has a height of 500px (height:500px) and you set the child to height:100% (which will work) then whatever content you put inside the child must fit inside that height:100% which will always be 500px. That’s fine until you enlarge the text or add more content.

There are other examples where having height defined is bad for the layout.

What most people mean when they want height:100% to work is that they want to match the height of perhaps of one column to another and assume that they can do this by basing the elements height on the height of the parent that holds both columns. In this case height:100% would be useful and indeed if you place an absolute element into that context it can keep track with a relatively positioned parents height (although it would be no good for adding content.)

For equal columns there are many tricks but the best way is the display:table/table-cell approach although that comes with a few caveats when trying to style or position.

Height when use in tables (and display:table etc) or table-cells is treated as a minimum which means that it can always grow should content require it and the reason that cells can base their height on the tables height (otherwise tables wouldn’t work).

All in all height is quite a complicated subject but I agree there are times when it would be useful to simply specify 100% and make the element fill the available space. The reason this is not available is because of the circular references needed to make this work and because most likely it would harm more than it cures.

Flexbox addresses most of this problems but in my mind adds to much complexity to the problem. Most times I try to use flexbox to do something I come back to display:table because it does what I want in a more robust way.

We have vh units now which will do this although again this throws up more queries. I’ve seen this a hundred times now and someone has an element half way down the page and they give it 100% height (or 100vh) and expect the element to reach the bottom of the viewport when in reality what they really want is for the element to stretch from where it is until it reaches the bottom. What they end up with is an element that goes 100% from where it is which means it finished way below the fold.

It would be nice for height to act in different ways but when you look at the specifics there isn’t really one way for the same property to do it all. It could be better but understanding how it works does help us to do the things we want even if sometimes it’s not as easy as it should be.

3 Likes

Nice answer.

I can’t shake the feeling that CSS could be made more flexible and intuitive though. I’m tempted to have a go by using JavaScript to process some CSS based markup to size and position elements in a similar way to described above, just to see if it can be done. I don’t have time though :frowning:

Hi Paul,
That hover/click area can fill the anchor by giving it an overflowing padding that is then clipped by its parent, the list-item. E.g. your code:

[code]

Untitled Document .bigBox{ border:1px solid red; padding:10px; } .nav{ display:table; border-collapse:collapse; width:75%; margin:auto; } .nav li{ display:table-cell; border:1px solid #666; overflow:hidden; vertical-align:middle; text-align:center; } .nav a{ display:block; margin:-100px; padding:105px 102px; background:red; color:#fff; text-decoration:none; } .nav a:hover{background:blue} @media screen and (max-width:500px){ .nav li{display:block;} }
  • Home
  • Features
  • Experts Team Starring
  • Quiz
  • Projects
  • Horoscopes
  • [/code] Finally made it back, sort of. :)

    Erik, is that really you? I thought something catastrophic had happened to you. Welcome back indeed:)

    Yes I often forget about the excessive padding negative margin trick due to it’s problem with fragment identifiers but that won’t be an issue in this case so your demo will work well :smile:

    This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.