How to use CSS calc() with an element's height

HtmlCss

Html Problem Overview


I was studying ways to make a hexagon with just CSS, and found a solution that gives me regular hexagons based on the width:

.hexagon {
  height: 100%;
  width: calc(100% * 0.57735);
  display: inline-block;
}

However, the code works by generating new rectangles based on the parent element's width. I was searching for a way to calculate the width based on the parent's height.

Is there a way to use an element's height property instead of width for calc()? (I'm not looking into using vh since the nearest parent won't always be the viewport). I googled around and could not find an answer.

Html Solutions


Solution 1 - Html

I think you are trying to run script in a css syntax, which is NOT POSSIBLE.

calc() can do basic math operation with absolute values, it cannot find the height of an element and then perform math on it.

Solution 2 - Html

You can circumvent the problem using an intermediary: CSS variables, which is the only data "outside" the curly brackets, as it were.

If the parent's width is also dynamic or dependant on other value, use another var for that. Just as an example so you can see the syntaxis, it'd look something like this:

:root {
  --hex-parent-height: 10px;
}

.hexagon.parent {
  /* ... */
  width: var(--hex-parent-height);
}

.hexagon {
  height: 100%;
  width: calc(100% * var(--hex-parent-height));
  display: inline-block;
}

CSS Variables have two types of scopes: global and local. Local vars will only work logically within the same selector, but global vars are the same through all your CSS. Declaring one or more variables globally is done through the root block, as shown in the code example.

Retrieving a var value as you can see is as easy as using the var() CSS function, which in case you don't know, has a very nice fallback feature.

For example, if you were to set --hex-parent-height dynamically and something goes wrong and the var is left unset, you may insert a default value to minimize the damages, like so: var(--hex-parent-height, 10px)

Solution 3 - Html

It is not possible as @YAMAN said but I have a trick to share with you just in case it works and help you.

top: calc(50% - 0.59em);

To test it, given a div with a size and a text inside, you can increase the font size, get manually the height and divide it by 2, replace the 0.59em by that value and you will probably see that they stays in the same px.

Notice that I already know that this is not 100% precise, but it does work quite decent for few scenarios, check it out for you, might suit your case or might not.

Solution 4 - Html

As noted many times by many people, it is not possible to set a width based on 100% height using pure CSS.

If you know or can figure out the aspect ratio, then you technically know the width, and you can calculate it fairly easily.

.wrapper {
    position: relative;
    width: 100%;
    padding-top: 56.25%; /* 16:9 or widescreen aspect ratio */
}
.hexagon {
    top: 0;
    position: absolute;
    width: calc(100% * 9 / 16); /* or simply 56.25%; */
}

If the aspect ratio is unknown, then the only viable solutions using CSS is to set the height (or min-height) of the parent element using px or em values. These can also be set using CSS variables, although CSS variables are not fully supported by some older browsers.

.wrapper {
    min-height: 400px;
}
.hexagon {
    width: calc(400px * 0.57735);
}

Finally, if the height is completely dynamic, for instance it changes based on the number of lines of text, then the width will need to be calculated using javascript.

// Example using jQuery, but the principles should be the same.
jQuery(function($){
    var hexagon = $('.hexagon');
    // Resizing the document may change the height of the parent element.
    $(window).on('resize', function() {
        hexagon.each(function(){
            // We'll remove the existing width before calling parent.height()
            $(this).css({width:''}).css({width:$(this).parent().height()});
        });
    }).trigger('resize');
});

Please note that the javascript solution may not provide the exact results you are looking for if the size of the parent element changes when the child element changes. This is also part of the challenge with using height values with CSS and why almost everything is based on width instead.

Solution 5 - Html

I suggest to define a css rule which depends on a css var (as proposed by Carles Alcolea) and implement a javascript code which updates the value of the css var.

  1. Define css which uses var()
.hexagon.parent {
  /* ... */
  width: var(--hex-parent-height);
}
  1. Create a placeholder within the html to hold var(s) definition
<style id="my-dyn-css">
/* dynamically define css vars here */
</style>
  1. Define a function to set and update the values of the vars (for example on window resize)
function updateDynCss() {
  var parentHeight = computeHeight();
  var style = ":root{--hex-parent-height:" + parentHeight + "px;}";
  $("#my-dyn-css").empty().html(style);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLucianoView Question on Stackoverflow
Solution 1 - HtmlYAMANView Answer on Stackoverflow
Solution 2 - HtmlNeithan MaxView Answer on Stackoverflow
Solution 3 - HtmlAlejandro LoraView Answer on Stackoverflow
Solution 4 - HtmlShaun CockerillView Answer on Stackoverflow
Solution 5 - HtmlAntonio CapaniView Answer on Stackoverflow