I have a div with this css rule:
.somediv {
aspect-ratio: 1 / 3 !important;
}
I want to make the height equal not exactly (3 * width), but plus 8 pixels. For example, if my width is 10px, the height have to be like (10*3)+8 = 38 pixels. How can i do this, i know about calc() in css, but not sure it works with aspect-ratio.
If you are to set a fixed width , you may use CSS var() to set the width, then use calc() for aspect-ratio
examples
:root {
--width: 80;
}
div {
margin: 1em;
border: solid;
width: calc(var(--width) * 1px);
aspect-ratio: var(--width) / calc(var(--width) * 3 + 8);
/* demo purpose */
float: left;
}
div:before{
content:attr(style);
<div>défault</div>
<div style="--width:100"> </div>
<div style="--width:101"> </div>
<div style="--width:70"> </div>
<div style="--width:90"> </div>
If width is not, then javascriipt will be required
You can add a padding-top on the element you are styling for its size. It's counter intuitive because the size is supposedly ruled by the element width and its aspect-ratio but as you can see here in this demo, I show the computed width and height of the elements inside an ::after pseudo element through a data attribute I set via javascript with the actual offsetWidth and offsetHeight.
Given the width as 100px the height is indeed width*3 + 8px = 308px
const target = document.querySelector('div');
target.dataset['width'] = `${target.offsetWidth}px*${target.offsetHeight}px`;
.width-100{
width: 100px;
}
.ratio-1over3 {
aspect-ratio: 1 / 3;
padding-top: 8px;
}
.outline{
outline: solid red;
}
.ratio-1over3::after {
content: attr(data-width);
display: block;
}
<div class="ratio-1over3 width-100 outline">
</div>
You could use two <div>, a parent, with the dimensions and the aspect ratio, and a child with the calc():
.somediv {
width: 100%; /* or any width you want */
height: auto;
aspect-ratio: 1 / 3 !important;
}
.somediv__inner {
width: 100%;
height: calc(100% + 8px);
background: blue;
}
<div class="somediv">
<div class="somediv__inner"></div>
</div>
Related
This question already has answers here:
CSS: Width in percentage and Borders
(5 answers)
How do I add 1px border to a div whose width is a percentage?
(3 answers)
Closed 3 years ago.
I am creating an overlay but the width ends up wrong on the right. Where do I go wrong? In the end I want some buttons that are 100% width of the screen, minus some margin.
body
{
width: 100%;
margin: 0px;
}
.a1
{
background-color: rgba(0, 0, 0, 0.7);
position: fixed;
width: 100%;
height: 100%;
z-index: 1;
}
.a2 {
width: 100%;
border: 5px solid blue;
}
<div class="a1">
<div class="a2">The width is going to far on the right</div>
</div>
You don't need to specify width: 100% on the child div a2. As a block element, it will automatically fill the available width of the parent element, which is set at 100%.
Your a2 CSS becomes:
.a2 {
border: 5px solid blue;
}
In this way your margins are respected and work as expected:
* {
box-sizing: border-box;
}
body
{
width: 100%;
margin: 0px;
}
.a1
{
background-color: rgba(0, 0, 0, 0.7);
position: fixed;
width: 100%;
height: 100%;
z-index: 1;
}
.a2 {
border: 5px solid blue;
}
<div class="a1">
<div class="a2">The width is going to far on the right</div>
</div>
Following OP comment about sizing of elements
I notice that you don't specifically mention that you are using border-box as your box-sizing methods. I have added this into the snippet now.
Using border-box means that when you specify the size of a box, you are including the borders inside that size.
For example, if the width is set to 100%, this is 100% including any borders you have on your elements. Most normalized stylesheets set box-sizing to border-box by default.
So I created a box with 2 div tags, namely: outer div and box div.
The total width(content block) of my outer div is 600w+50padLeft+50padRight= 700px. Meanwhile the total width of my box div (containing block) is 500w+98padL+98padR+4border = 700px.
Yet, my box is overflowing in the outer div.
Here is the image:
https://www.flickr.com/photos/183721425#N02/48599642452/in/dateposted-public/
aside,
article,
section,
header,
footer,
nav {
display: block;
}
div,
p {
margin: 0;
padding: 0;
}
html {
background: #ccc;
}
.outer {
/* TOTAL WIDTH: 700px */
width: 600px;
margin: 0 auto;
background: #9CF;
padding: 50px;
}
.box {
background: #B7D19C;
/* TOTAL WIDTH: 700px */
width: 500px;
padding: 98px;
border: 2px black solid;
}
p {
background: #FF9;
height: 100%;
/* here */
}
<div class="outer">
<div class="box">
<p>Here we'll need to calculate the width of this interior div element. This may seem simple at first, but as we begin to add box model properties, and as the overall width of the parent element and the div conflict with one another, we'll need to understand
how each of the properties combine to effect the overall width (and height) of page elements.
</p>
</div>
</div>
Use box-sizng:border-box property.
It defines how the width and height of an element are calculated, should they include padding and borders, or not. Margin is not considered. Usually the size (width or height) of the element not include border or padding
*{
box-sizing: border-box;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>calculating element dimensions</title>
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<style>
aside,
article,
section,
header,
footer,
nav {
display: block;
}
div,
p {
margin: 0;
padding: 0;
}
html {
background: #ccc;
}
.outer {
/* TOTAL WIDTH: 700px */
width: 600px;
margin: 0 auto;
background: #9CF;
padding: 50px;
}
.box {
background: #B7D19C;
/* TOTAL WIDTH: 700px */
width: 500px;
padding: 98px;
border: 2px black solid;
}
p {
background: #FF9;
height: 100%;
/* here */
}
/*add styles here*/
</style>
</head>
<body>
<div class="outer">
<div class="box">
<p>Here we'll need to calculate the width of this interior div element. This may seem simple at first, but as we begin to add box model properties, and as the overall width of the parent element and the div conflict with one another, we'll need to
understand how each of the properties combine to effect the overall width (and height) of page elements.
</p>
</div>
</div>
</body>
</html>
Problem :
Your issue is with the box model itself as by default the border and the padding are not included in the actual elements width :
.outer has a width of 600px and has a 50px of padding (total width is 600px + 50px right padding + 50px left padding = 700px) so the .box will be shifted 50px to the right.
.box has 500px for the width, 98px for the padding and a 2px border which results in a 500px + 98px right padding + 98px left padding + 2px left border + 2px right border =700px.
the widths are equal but don't forget about the 50px of padding on the .outer that results on an overflow.
Solution :
The solution is very simple, add box-sizing: border-box on the two divs (better to use it on all the elements) which includes the padding and border on the width (meaning the padding and border won't overflow the declared width).
* {
box-sizing: border-box; /** that's it ! **/
}
aside,
article,
section,
header,
footer,
nav {
display: block;
}
div,
p {
margin: 0;
padding: 0;
}
html {
background: #ccc;
}
.outer {
/* TOTAL WIDTH: 700px */
width: 600px;
margin: 0 auto;
background: #9CF;
padding: 50px;
}
.box {
background: #B7D19C;
/* TOTAL WIDTH: 700px */
width: 500px;
padding: 98px;
border: 2px black solid;
}
p {
background: #FF9;
height: 100%;
/* here */
}
<div class="outer">
<div class="box">
<p>Here we'll need to calculate the width of this interior div element. This may seem simple at first, but as we begin to add box model properties, and as the overall width of the parent element and the div conflict with one another, we'll need to understand
how each of the properties combine to effect the overall width (and height) of page elements.
</p>
</div>
</div>
I am having trouble placing a container on top of another container that uses a clipped-path. I have tried using z-index on either of the containers but it doesn't seem to help.
If I remove the clipped-path class from the container then the block slides happily over the container. I have included a fiddle of my problem.
Here is my code:
window.onscroll = function(){
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
var para = Math.round(scrollTop / 1.2);
document.querySelector('#block').style.transform = "translate3d(0px," + para + "px,0px)";
}
body {margin: 5px;}
#main {height:100vh;}
#below-main {height:100vh;}
#row1 {height:100vh;}
/* Paralellogram to slide underneath block
--------------------------------------------- */
#bluestripe {
height: 60vh;
width:60vw;
margin: 0 auto;
}
img {width: 100%;}
.clip-polygon {clip-path: polygon(100% 0, 100% 40%, 0 100%, 0 60%);}
/* Block to sit above parallelogram
--------------------------------------------- */
#block {
height: 50px;
width:100px;
margin: 50px auto 0 auto;
transform: translate3d(0px,0px,0px);
background-color: #999;
}
<body>
<div id="main">
<div id="block">This needs to slide on top</div>
<div id="bluestripe">
<img id="sea" src="https://images.pexels.com/photos/6644/sea-water-ocean-waves.jpg?w=940&h=650&auto=compress&cs=tinysrgb" alt="" class="clip-polygon">
</div>
<div id="row1"></div>
</div>
</body>
To affect an element's z-index, it must have position set to something other than static (the default).
In the case of your #block, it has no position set, so it is using the layer implied by the element's order in the source: it appears in your source before your clipped element, and naturally settles below it.
To position it on a higher z-index in the stack, give it a position and a z-index:
#block {
height: 50px;
width: 100px;
margin: 50px auto 0 auto;
transform: translate3d(0px,95px,0px);
background-color: #999;
position: relative; /* Allows z-index to take affect */
z-index: 2; /* Stacks it above the clipped layer, which has no position nor z-index and is at z-index 1 */
}
This question already has answers here:
Setting Element Width Based on Height Via CSS
(10 answers)
Closed 3 years ago.
I saw solution for height depending on width: css height same as width. Or here: https://stackoverflow.com/a/6615994/2256981.
But my question is opposite.
My element:
<body>
<div id="square"></div>
</body>
Style for it:
body, html {
margin: 0;
height: 100%;
min-height: 300px;
position: relative;
}
div#square { /* My square. */
height: 75%; /* It's height depends on ancestor's height. */
width: 75vh; /* If supported, preliminarily sets it's width. */
position: absolute; /* Centers it. */
left: 50%; top: 50%; transform: translate(-50%, -50%);
background-color: darkorange; /* Makes it visible. */
}
Script, that keeps it square:
window.onload = window.onresize = function (event) {
var mySquare = document.getElementById("square");
mySquare.style.width = mySquare.offsetHeight + 'px';
};
Complete code here: http://jsfiddle.net/je1h/hxkgfr9g/
The question is to make the same thing in pure CSS. No scripting.
There are two techiques I am aware of to keep the aspect ratio of an element according to it's height :
When height is relative to the viewport :
You can use vh units :
div {
width: 75vh;
height: 75vh;
background:darkorange;
}
<div></div>
For a height based on the height of a parent element :
You can use a dummy image that has the aspect ratio you want. Example with a 1:1 aspect ratio you can use a 1*1 transparent .png image or as commented by #vlgalik a 1*1 base64 encoded gif :
html,body{
height:100%;
margin:0;
padding:0;
}
#wrap{
height:75%;
}
#el{
display:inline-block;
height:100%;
background:darkorange;
}
#el img{
display:block;
height:100%;
width:auto;
}
<div id="wrap">
<div id="el">
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
</div>
</div>
Note that this last demo doesn't update on window resize. But the aspect ratio is kept on page load
UPDATE :
As reported in the comments setting display:inline-flex: on #el seems to solve the updating on window resize problem.
Edit: Missed that you wanted to set the width depending of the height, this does the opposite :(
To support all ratios you can use padding-bottom. Percentages in padding-bottom are always relative to the width of the element:
/* the wrapper has a width */
.wrapper {
position: relative;
width: 25%;
margin-bottom: 10px;
}
/* these elements set the height (using padding-bottom) */
.square {
padding-bottom: 100%;
position: relative;
}
.widescreen {
padding-bottom: 56.25%; /* 9/16 = 0.5625 */
}
/*
* This is the content.
* Needs position:absolute to not add to the width of the parent
*/
.content {
/* fill parent */
position: absolute;
top: 0; bottom: 0;
left: 0; right: 0;
/* visual */
padding: 10px;
background: orange;
color: white;
}
<div class="wrapper">
<div class="square">
<div class="content">square</div>
</div>
</div>
<div class="wrapper">
<div class="widescreen">
<div class="content">16:9 ratio</div>
</div>
</div>
The only downside is, that you need a bunch of wrapper elements.
I am trying to dynamicly change the width of a div using CSS and no jquery. The following code will work in the following browsers: http://caniuse.com/calc
/* Firefox */
width: -moz-calc(100% - 500px);
/* WebKit */
width: -webkit-calc(100% - 500px);
/* Opera */
width: -o-calc(100% - 500px);
/* Standard */
width: calc(100% - 500px);
I want also support IE 5.5 and higher, i found the following: expression. Is this the correct usage:
/* IE-OLD */
width: expression(100% - 500px);
Can I also support Opera and the Android browser?
Almost always box-sizing: border-box can replace a calc rule such as calc(100% - 500px) used for layout.
For example:
If I have the following markup:
<div class="sideBar">sideBar</div>
<div class="content">content</div>
Instead of doing this: (Assuming that the sidebar is 300px wide)
.content {
width: calc(100% - 300px);
}
Do this:
.sideBar {
position: absolute;
top:0;
left:0;
width: 300px;
}
.content {
padding-left: 300px;
width: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
* {
margin: 0;
padding: 0;
}
html,
body,
div {
height: 100%;
}
.sideBar {
position: absolute;
top: 0;
left: 0;
width: 300px;
background: orange;
}
.content {
padding-left: 300px;
width: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: wheat;
}
<div class="sideBar">sideBar</div>
<div class="content">content</div>
PS: I won't work in IE 5.5 (hahahaha) , but it will work in IE8+ , all mobile, and all modern browsers (caniuse)
Width Demo
Height Demo
I just found this post from Paul Irish's blog where he also shows off box-sizing as a possible alternative for simple calc() expressions: (bold is mine)
One of my favorite use-cases that border-box solves well is columns. I
might want to divide up my grid with 50% or 20% columns, but want to
add padding via px or em. Without CSS’s upcoming calc() this is
impossible… unless you use border-box.
NB: The above technique does indeed look the same as would a corresponding calc() statement. There is a difference though. When using a calc() rule the value of the width of the content div will actually be 100% - width of fixed div, however with the above technique, the actual width of the content div is the full 100% width, yet it has the appearance of 'filling up' the remaining width. (which is probably good enough for want most people need here)
That said, if it is important that the content div's width is actually 100% - fixed div width then a different technique - which makes use of block formatting contexts - may be used (see here and here for the gory details):
1) float the fixed width div
2) set overflow:hidden or overflow:auto on the content div
Demo
Just have a fallback before the calc will do the trick.
width: 98%; /* fallback for browsers without support for calc() */
width: calc(100% - 1em);
See more here https://developer.mozilla.org/en-US/docs/Web/CSS/calc
use this
.content
{
width: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding-right: 500px;
margin-right: -500px;
}
Just spent the best part of 3 hours trying to workaround this for a specific case on andriod devices, couldnt get box sizing to work so i've linked it into my JS as a dirty workaround... no jQuery required though! :)
Taken on working code on andriod 2.3.
<div class="sessionDiv" style="width:auto;">
<img> <!-- image to resize -->
</div>
<div class="sessionDiv" style="width:auto;">
<img> <!-- image to resize -->
</div>
JS with event listeners
var orient =
{
orientation:window.orientation,
width: window.innerWidth,
check: function()
{
// if orientation does not match stored value, update
if(window.orientation !== this.orientation)
{
this.orientation = window.orientation; //set new orientation
this.width = window.innerWidth; //set new width
this.adjustIrritatingCSS(this.width); //change ui to current value
}
//if width does not match stored value, update
if(window.innerWidth !== this.width)
{
this.width = window.innerWidth; //set new width
this.adjustIrritatingCSS(this.width); //change ui to current value
}
},
adjustIrritatingCSS: function(screenWidth)
{
//disgusting workaround function
var titleBoxes = document.getElementsByClassName('sessionDiv');
var i = titleBoxes.length;
var sessWidth = screenWidth - 300; // calc(100% - 300px); -> equivalent
while(i--)
{
titleBoxes[i].style.width = String( sessWidth + "px");
//resize image in auto sized div
}
sessWidth = null; //clear width
titleBoxes = null; //clear nodelist
i = null; // clear index int
}
};
window.onload = function()
{
window.addEventListener('resize', function(){orient.check();});
//on resize, check our values for updates and if theres changes run functions
window.addEventListener('orientationchange', function(){orient.check();});
//on rotate, check our values for updates and if theres changes run functions
setInterval(function(){orient.check();}, 2000);
//occasionally check our values for updates and if theres changes run functions(just incase!!)
orient.adjustIrritatingCSS(orient.width);
//sets value on first run
};
Hope this helps anyone who cant get the box-sizing working!
PS I have experienced problems with ios using this...
Change #menuLog width with % or px and you will see magic. Works with every device even < 2.3
*{
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
#menuLog{
width:30%;
/*width:300px;*/
height: 60px;
padding: 5px;
background-color: #ddd;
}
#menuLog > div[inline-log="1"]{
display: inline-block;
vertical-align: top;
width: 100%;
height: 100%;
margin-right: -60px;
}
#menuLog > div[inline-log="1"] > div[inline-log="1.1"]{
margin-right: 60px;
height: 100%;
background-color: red;
}
#menuLog > div[inline-log="2"]{
display: inline-block;
vertical-align: top;
width: 60px;
height: 100%;
}
#menuLog > div[inline-log="2"] > div[inline-log="2.1"]{
display: inline-block;
vertical-align: top;
width: 55px;
height: 100%;
background-color: yellow;
margin-left:5px;
}
<div id="menuLog">
<div inline-log="1">
<div inline-log="1.1">
One
</div>
</div><div inline-log="2">
<div inline-log="2.1">
Two
</div>
</div>
</div>
I wanted to add the no-calc, no-border-box (i.e., CSS2) alternative.
Normal-flow block elements initially have width: auto, which is effectively the width of the containing block minus the margin, border, and padding widths.
The example above can be done, without border-box, simply as
.content {
padding-left: 300px;
}
Similarly, with
.content {
margin-left: 1px;
border-left: 1em solid;
padding-left: 1rem;
}
the effective width is 100% - 1px - 1em - 1rem.
For absolutely positioned elements, height: auto has similar properties:
.content {
position: absolute;
top: 0;
bottom: 0;
margin-bottom: 1px;
border-bottom: 1em solid;
padding-bottom: 1rem;
}
Here the effective height is 100% - 1px - 1em - 1rem.