Is it possible to use CSS calc() in order to calculate an width/height ratio? - css

This is the code which I currently have (it does not work yet):
HTML:
<div class="chi_display_header" style="background-image:url('http://localhost/.../header-dummy-small.png');"></div>
CSS:
.chi_display_header {
background-size:contain;
width:100%;
min-height:100px;
height:calc(1vw * 270 / 1280px);
max-height:270px;
max-width:1280px;
margin:0 auto;
}
This is a centered responsive background image - the container should have a variable width / height and I do not want to use jQuery.
Known properties:
Ratio: 1280:270
Minimum height: 100px
Maximum height: 270px
Maximum width: 1280px
What I try to do is to calculate the container height of .chi_display_header magically with calc:
height = calc( CURRENT_SCREEN_WIDTH * 270 / 1280);
However my current approach
height:calc(1vw * 270 / 1280px);
does not work yet. Is there a CSS solution?

Solution (ty 4 comments):
.chi_display_header {
background-size:cover;
width:100%;
min-height:100px;
height:calc(100vw * 270.0 / 1280.0);
max-height:270px;
max-width:1280px;
margin:0 auto;
}

I applied Blackbam's solution to the situation where a div was placed in the body and the body had left and right padding of 15px. Subtracting the total left and right padding (30px) from the calculated height removed white-space that appeared above and below the div.
height:calc(100vw * aspect_ratio - 30px);

It's possible to do this without calc() as well. padding (even -top and -bottom) are relative to the element's width, so you can get the same effect thus:
.chi_display_header {
background-size: cover;
width: 100%;
min-width: 474px;
max-width: 1280px;
height: 0;
padding-bottom: 21.09375%;
}
You can also add elements inside with an inner <div> using the relative/absolute trick, though things will begin to go awry if the content exceeds the containing height:
.chi_display_header {
...
position: relative;
}
.chi_display_header .inner {
position: absolute;
top: 0; left: 0; right: 0;
padding: 15px;
}

Related

Evaluating percentages to pixels in SASS

Currently, I'm setting a variable to correspond to a circle's width and height, like so:
$circle-diameter: 70%;
.circle {
width: $circle-diameter;
height: $circle-diameter;
}
However, the circle's width becomes 70% of the parent element's width, and the height becomes 70% of the parent element's height, which yields an oval that is wider than it is tall. Ideally, I'd like to convert .circle-diameter to a fixed size and assign the circle's width and height to that fixed size. Is there a solution for this in CSS/SASS?
You can use padding-top instead of height, it will work because padding is relative to parent width.
.circle{
width: 70%;
padding-top: 70%;
/* height: 0; */
}
http://codepen.io/yukulele/pen/PzGgNM
What you are looking for is to have a fixed ratio between width and height. For a circle tho, the width/height ratio is 1. There's a hacky way to accomplish that task. First I'd like to write a css class that always provides us a space that has width/height ratio of 1. To do so:
See Fiddle
Why this works? Because, If you use percentage based units on padding, It always be relative to element's width. See reference
Next I always like to use absolute hack to provide myself a workaround in that nicely 1/1 ratio square that we've create.
See Fiddle 2
Using position: absolute for our own good, we've created a element that has a fixed ratio and has a working width/height properties.
After It depends on what you need to do. In your case I've created a nice circle for to examine the situation.
See Fiddle 3
Working source code
**Css**
.ratio-1 {
position: relative;
width: 100%;
padding-top: 100%;
background-color: silver;
}
.im-something-has-some-width {
width: 200px;
border: 3px solid lime;
}
.space-provider {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.yay-i-have-a-square-field {
// lets use it for our own goods!
width: 100%;
height: 100%;
background-color: skyblue;
border-radius: 50%;
}
Html
<div class="im-something-has-some-width">
<div class="ratio-1">
<div class="space-provider">
<div class="yay-i-have-a-square-field">
</div>
</div>
</div>
</div>

How can I fix errors created when using a non-exact decimal in CSS?

I've used the 'target / context = result' trick on a site I'm developing, but I've run into a fairly large issue: the equation returns a percent so long, I can't find a calculator to complete the equation without rounding. As you can see below, I've set the height to a percent instead of auto, as if the value is auto, it will chop of the bottom part of the div, which I need. So, I've set it to the nearest rounded decimal - looks fine at first, then resize and it becomes larger/smaller than I need it to be. For reference for what it should look like, it should be the same height as image next to it. I can't provide the image for copyright reasons, but the image size is 800 by 440 pixels. Just apply the second rule to it. Thanks.
#comment-1 {
width: 6.25%;
height: 30.09781790820166%;
padding: 20px;
float: left;
color: #FFF;
background-color: #CC521D;
font-family: "Lato", Arial, Helvetica, sans-serif;
font-size: 125%;
}
#image-1 {
width: 31.25%;
height: auto;
float: left;
margin-right: 20px;
}
EDIT: Just noticed, I forget to provide the context: the height is 1329px and the width is 2560px.
Height percent will be based on parent element width if parent element height was not set! That means you need another approach, one of the solutions would be: let your image container be relative, with padding left 6.25%, than your comment would be absolute with left, top, bottom: 0 (width can be calculated as 6.25/31.25*100). That way the image height would control comment height.
<style type="text/css">
.comment_and_image {
position: relative;
width: 31.25%;
padding-left: 6.25%;
float: left;
}
.comment {
width: 20%; /* 6.25/31.25*100 */
position: absolute;
left: 0;
top: 0;
bottom: 0;
}
.image {
height: auto;
width: 100%;
}
</style>
<div class="comment_and_image">
<div class="comment">text</div>
<img class="image" src="path_to_image.jpg" alt="Image" />
</div>
I've used skobaljic's answer, just a modified version. I've set the top and bottom rules to 0, as he said, but instead of leaving left at 0, I set the margin-left to 101.875, as it is the width of the image plus 15 pixels, exactly what I needed.

Maintain div aspect ratio according to height

I need to maintain the width of an element as a percentage of its height. So as the height changes, the width is updated.
The opposite is achievable by using a % value for padding-top, but padding-left as a percentage will be a percentage of the width of an object, not its height.
So with markup like this:
<div class="box">
<div class="inner"></div>
</div>
I'd like to use something like this:
.box {
position: absolute;
margin-top: 50%;
bottom: 0;
}
.inner {
padding-left: 200%;
}
To ensure the box's aspect ratio is maintained according to it's height. The height is fluid because of it's % margin - as the window's height changes, the box's height will too.
I know how to achieve this with JavaScript, just wondering if there's a clean CSS-only solution?
You can use an image that has the desired proportions as to help with proportional sizing (images can be scaled proportionally by setting one dimension to some value and other to auto). The image does not have to be visible, but it must occupy space.
.box {
position: absolute;
bottom: 0;
left: 0;
height: 50%;
}
.size-helper {
display: block;
width: auto;
height: 100%;
}
.inner {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(255, 255, 153, .8);
}
<div class="box">
<img class="size-helper" src="//dummyimage.com/200x100/999/000" width="200" height="100">
<div class="inner">
1. box has fluid height<br>
2. img has 2:1 aspect ratio, 100% height, auto width, static position<br>
2.1 it thus maintains width = 200% of height<br>
2.2 it defines the dimensions of the box<br>
3. inner expands as much as box
</div>
</div>
In the above example, box, inner and helper are all same size.
You can use vh units for both height and width of your element so they both change according to the viewport height.
vh
1/100th of the height of the viewport. (MDN)
DEMO
.box {
position: absolute;
height:50vh;
width:100vh;
bottom: 0;
background:teal;
}
<div class="box"></div>
There is another, more efficient way to achieve constant aspect ratio according to height.
You can place an empty svg so you dont have to load an external image.
HTML code:
<svg xmlns="http://www.w3.org/2000/svg"
height="100"
width="200"
class='placeholder-svg'
/>
CSS code:
.placeholder-svg {
width: auto;
height: 100%;
}
Change width/height to achieve desired aspect ratio.
Keep in mind, the svg might overflow.
http://www.w3.org/2000/svg is just a namespace. It doesn't load anything.
If you change placeholder-svg class to:
.placeholder-svg {
width: 100%;
height: auto;
}
then height is adjusted according to width.
Demo 1 Width is adjusted according to height and 2:1 aspect ratio.
Demo 2 same as above, but you can resize easily (uses React)
The CSS trick you wrote, works pretty well to keep ratio width / height on an element.
It is based on the padding property that, when its value is in percent, is proportional to parent width, even for padding-top and padding-bottom.
There is no CSS property that could set an horizontal sizing proportionally to the parent height.
So I think there is no clean CSS solution.
As of 2021 there is a property called aspect-ratio.
Most browsers support it
div {
border: 1px solid;
margin: 8px;
}
.box {
width: 100px;
min-height: 100px;
resize: horizontal;
overflow: auto;
}
.inner1 {
aspect-ratio: 1/1;
}
.inner2 {
aspect-ratio: 3/1;
}
<div class="box">
<div class="inner1"></div>
<div class="inner2"></div>
</div>
Run this snippet and resize the outer div manually to see the inner divs behavior
I can't find a pure CSS solution. Here's a solution using CSS Element Queries JavaScript library.
var aspectRatio = 16/9;
var element = document.querySelector('.center');
function update() {
element.style.width = (element.clientHeight * aspectRatio) + 'px';
}
new ResizeSensor(element, update);
update();
CodePen demo!

css relative alignment upon image

I am trying to align a div on top of my image. Horizontal alignment works fine, vertical offset however doesn't. Also, the background-color of #studentenlijn is not applied.
HTML Snippet:
<div id="container">
<div id="studentenlijn">STUDENTENLIJN</div>
<img src="http://lsvb.nl/s/lsvbheader.jpg" class="banner" />
</div>
Relevant CSS
#studentenlijn {
width: 10%;
height: 10%;
position: absolute;
top: 30%;
left: 72%;
background-color: #660000;
}
JSFiddle: http://jsfiddle.net/YGeLA/
Any ideas?
Your body had a height of 0, thus affecting the height of the containers within it when you try to specify a percentage height. Another problem was that you had a floating image within your container div, and thus you need to hide the overflow in order for the container to properly calculate the heights of elements within.
I have made some minor changes to your fiddle here:
http://jsfiddle.net/YGeLA/1/
I added:
height: 100%; to the body element
overflow: hidden; to #container which forces the container to respect the height of all elements within it.
The size of your div is:
#studentenlijn {
width: 10%;
height: 10%;
}
So it'll be a % of the parent element. The parent element, your container, is:
#container {
width: 100%;
height: 100%;
}
At this point, your browser can't determine which size should have your block.
So you won't be able to center it (Since you can't center an element which have not a browser-determined size).
You can't see the background-color for the same reason. It is applied, but you won't see your colored block because his size is 0.
Try to solve it, and it would be easier to center your div. In case it doesn't help you, edit your post with your modification :)
the container height is 0px. so you can't give height 100%
you have to set height in px
look at this update
#container {
position:relative;
width:100%;
height:100%;
line-height: 0;
}
.banner {
width:100%;
}
#studentenlijn {
width:200px;
height:30px;
position:absolute;
top:35px;
left:72%;
background-color:#660000;
line-height:30px
}
http://jsfiddle.net/YGeLA/2/

How to always center a flexible square in viewport with pure CSS?

I know this question: Height equal to dynamic width (CSS fluid layout)
But I want more!! I want a flexible container which has always the aspect ratio of a square but with max-height and max-width of 100% of the page (the window element) and on the top of it is always vertically and horizontally centered.
Like this:
// Container matches height of the window
// container-height = 100%; container-width = absolute-container-height
-page/browser-window-
- ####### -
- #cont-# -
- #ainer# -
- ####### -
---------------------
// container matches width of the window
// container-width = 100%; container-height = absolute-container-width
--page---
- -
- -
-#######-
-#######-
-#######-
-#######-
- -
- -
---------
Is it possible to achieve this with pure css (and even better cross-browser)?
Edit:
I know there is calc() for css3, but due to the poor mobile browser-support, I don't want to use it.
Edit2:
Seems like, I didn't make myself clear enough. I need height and width of the wrapper to match the height OR the width of the window, depending on which is smaller.The square-container should never exceed the smaller value of the window-height/width.
This is, how it would be done with jQuery:
// container/#main-wrapper has top: 50%, left: 50%, position: absolute via css
$(window).resize(function () {
var $ww = $(window).width();
var $wh = $(window).height();
if ($ww > $wh) {
$('#main-wrapper').css({
height: $wh,
width: $wh,
marginTop : ($wh / 2) * -1,
marginLeft : ($wh / 2) * -1
});
} else {
$('#main-wrapper').css({
height: $ww,
width: $ww,
marginTop : ($ww / 2) * -1,
marginLeft : ($ww / 2) * -1
});
}
});
I finally figured it out. The magic ingredients are the view-port units.
Given this html structure:
.l-table
.l-table-cell
.square
You can use this css (well actuall its scss, but you get the idea) to make it work
html,
body{
height: 100%
}
l-table{
background: orange;
display: table;
height: 100%;
width: 100%;
}
.l-table-cell{
display: table-cell;
vertical-align: middle;
border: 2px solid black;
}
.square{
background: red;
margin: auto;
#media (orientation:landscape) {
width: 70vh;
height: 70vh;
}
#media screen and (orientation:portrait) {
width: 70vw;
height: 70vw;
}
}
http://codepen.io/johannesjo/pen/rvFxJ
For those who need it, there is a polyfill.
EDIT: Since writing the below, I appealed on Twitter and got a response from Brian Johnson. He came up with a solution that isn't 100% perfect semantically, but it's pretty damn good and I'll certainly be using it. He asked that I share it in this discussion. LINK
I'm having the same issue right now and I was just typing out pretty much this exact question, so although I can't answer it, I wanted to share what I've found so far in case it helps anyone come up with the final solution.
To clarify, I need my content to fit into a square which fills 60% of the browser's width if portrait or 60% of the height if landscape.
However, this square must never exceed the width or height of the viewport.
Using the technique found here I've managed to create the fluid square, but it still exceeds the viewport when landscape.
width: 60%;
height:0;
padding-bottom: 60%;
Link to Codepen example
I have tried flipping that technique on it's side for landscape but that doesn't work. (You can see that code in the above example, noted out.)
I can't use a simple max-height property because the height is being worked out by the padding-bottom property.
I've thought about adding an extra div as someone else has suggested (C-Link's post is really interesting) but I can't work out how I'd get it to do what we want it do here.
html
<div id="outer">
<div id="inner">YOUR CONTENTS HERE
</div>
</div>
css
html, body{
height: 100%;
}
#outer{
max-height: 100%;
max-width: 100%;
position: relative;
height: 100%;
}
#inner{
position: relative;
top: 50%;
margin-top: -50% auto auto auto;
background: red;
text-align: center;
color: yellow;
}
See this fiddle.
How about if you take the earlier concept a step further with a similar div as a container. The container has an added max-height & width. I tried this and the container does not throw a scrollbar at me. It is quite interesting in behavior I must say myself. Does this work for you?
<div id="container">
<div id="centered">A DIV</div>
</div>
#container {
top:0;
bottom:0;
right:0;
left:0;
margin:auto;
position:absolute;
width:200px;
height:200px;
max-width:100%;
max-height:100%;
background:#00f;
padding:0;
}
#centered {
background: green;
bottom: 0;
height: 80px;
left: 0;
margin: auto;
position: absolute;
top: 0;
right: 0;
width: 80px;
}
updated fiddle:
http://jsfiddle.net/djwave28/mBBJM/96/

Resources