Is it possible to implement the following logic usic HTML and CSS?
width: 100%;
height: 30% of width;
What I want to implement:
If I decrease the width, the height will also decrease proportionally.
Padding %
This can be achieved by giving the element height:0 and padding-bottom:30%.
In all browsers, when padding is specified in %, it's calculated relative to the parent element's width. This can be a very useful feature for Responsive Design.
JSFiddle Demo
In the demo, the blue box at the top of the page is a single div. The height is responsive, and it can contain a variable amount of inline content without increasing the height. It tested fine in IE7/8/9/10, Firefox, Chrome, Safari, and Opera.
.content {
width: 100%;
height: 0;
padding-bottom: 30%;
}
...
<div class="content"></div>
Padding % and absolute position
If there are any problems with using a 0-height element, the demo also has a green box that's implemented using a wrapper element and absolute position. Not sure if there are any advantages to this approach.
.wrapper {
position: relative;
width: 100%;
padding-bottom: 30%;
}
.wrapper .content {
position: absolute;
width: 100%;
height: 100%;
}
...
<div class="wrapper">
<div class="content"></div>
</div>
This is now possible on modern browsers with vw and vh units:
width: 100vw;
height: 30vw; /* 30% of width */
Browser support: http://caniuse.com/#feat=viewport-units
Yeah!
Also with JQuery, you could do:
$(window).ready(function () {
var ratio = 3 / 10, $div = $('#my_proportional_div');
$div.height($div.width() * ratio);
$(window).bind('resize', function() { $div.height($div.width() * ratio); });
});
because the Padding % solution suggested doesn't work with max/min-width and max-min height.
Related
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!
How can I scale a div to fit inside the browser view port but preserve the aspect ratio of the div. How can I do this using CSS and/or JQuery?
Thanks!
You don't need javascript for this. You can use pure CSS.
A padding-top percentage is interpreted relative to the containing block width. Combine it with position: absolute on a child element, and you can put pretty much anything in a box that retains its aspect ratio.
HTML:
<div class="aspectwrapper">
<div class="content">
</div>
</div>
CSS:
.aspectwrapper {
display: inline-block; /* shrink to fit */
width: 100%; /* whatever width you like */
position: relative; /* so .content can use position: absolute */
}
.aspectwrapper::after {
padding-top: 56.25%; /* percentage of containing block _width_ */
display: block;
content: '';
}
.content {
position: absolute;
top: 0; bottom: 0; right: 0; left: 0; /* follow the parent's edges */
outline: thin dashed green; /* just so you can see the box */
}
The display: inline-block leaves a little extra space below the bottom edge of the .aspectwrapper box, so another element below it won't run flush against it. Using display: block will get rid of it.
Thanks to this post for the tip!
Another approach relies on the fact that browsers respect an image's aspect ratio when you resize only its width or height. (I'll let google generate a 16x9 transparent image for demonstration purposes, but in practice you would use your own static image.)
HTML:
<div class="aspectwrapper">
<img class="aspectspacer" src="http://chart.googleapis.com/chart?cht=p3&chs=160x90" />
<div class="content">
</div>
</div>
CSS:
.aspectwrapper {
width: 100%;
position: relative;
}
.aspectspacer {
width: 100%; /* let the enlarged image height push .aspectwrapper's bottom edge */
}
.content {
position: absolute;
top: 0; bottom: 0; right: 0; left: 0;
outline: thin dashed green;
}
Thanks to Geoff for the tip on how to structure the math and logic. Here's my jQuery implementation, which I'm using to size a lightbox so it fills the window:
var height = originalHeight;
var width = originalWidth;
aspect = width / height;
if($(window).height() < $(window).width()) {
var resizedHeight = $(window).height();
var resizedWidth = resizedHeight * aspect;
}
else { // screen width is smaller than height (mobile, etc)
var resizedWidth = $(window).width();
var resizedHeight = resizedWidth / aspect;
}
This is working well for me right now across laptop and mobile screen sizes.
I have a different pure HTML/CSS approach which does not rely on padding or absolute positioning. Instead it uses em units and relies on the CSS min() function plus a little bit of math.
Imagine that we want a viewport div with 16:9 aspect ratio which always fits the browser window and is centered in the axis with excess space. Here's how we can accomplish that:
HTML
<body>
<div class="viewport">
<p>
This should be a 16:9 viewport that fits the window.
</p>
</div>
</body>
CSS
body {
width: 100vw;
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: white;
font-size: min(1vw, 1.778vh);
}
div.viewport {
width: 100em;
height: 56.25em;
background-color: lightblue;
}
div.viewport > p {
font-size: 3em;
text-align: center;
}
You can experiment with this in a sample JSFiddle here.
The secret sauce is in the body font-size. It should be set to min(1vw, Avh), where A is the aspect ratio you want the div to have, i.e. width / height. In the example above we're using 1.778, which is approximately 16 / 9.
In CSS, em units are based on the font-size of the element, which is inherited from parent element if not explicitly set. For your viewport div, set the width to 100em (NOT rem) and the height to Iem, where I is the inverse of the aspect ratio expressed as a percentage, i.e. 100 / A or 100 * height / width. In the example above we're using 56.25, which is 100 * 9 / 16.
One bonus of this approach is that all of your nested elements may also use em units so that they always scale precisely with the size of the viewport. You can see this used on the p element in the example.
Note that as an alternative to the above, you may set the font-size on your html element and use rem units everywhere. CSS rem units are similar to em units but always relative to the root element's font-size.
Javascipt:
//Responsive Scaling
let outer = document.getElementById('outer'),
wrapper = document.getElementById('wrap'),
maxWidth = outer.clientWidth,
maxHeight = outer.clientHeight;
window.addEventListener("resize", resize);
resize();
function resize(){
let scale,
width = window.innerWidth,
height = window.innerHeight,
isMax = width >= maxWidth && height >= maxHeight;
scale = Math.min(width/maxWidth, height/maxHeight);
outer.style.transform = isMax?'':'scale(' + scale + ')';
wrapper.style.width = isMax?'':maxWidth * scale;
wrapper.style.height = isMax?'':maxHeight * scale;
}
HTML:
<div id="wrap">
<div id="outer">
{{ fixed content here }}
</div>
</div>
Styling:
/* Responsive Scaling */
#wrap {
position: relative;
width: 1024px;
height: 590px;
margin: 0 auto;
}
#outer {
position: relative;
width: 1024px;
height: 590px;
transform-origin: 0% 0%;
overflow: hidden;
}
This is possible with JQuery and a bit of maths.
Use JQuery to get the view ports width and height as well as the divs current dimensions.
$(document).width();
Calculate the divs current aspect ratio. eg width/height
You need a bit of logic to determine whether to set the width or height first, then use the initial ratio to calculate the other side.
jQuery has a plugin that grows an object until one of it's sides reaches a certain px-value. Coupling this will the viewport's height, you could expand any element to that size: jQuery MaxSide.
I have a wrapper div with a max-width of 1000px and max-height of 650px.
I want to dynamically adjust the width and height of this wrapper while maintaining its aspect ratio. If the browser window is re-sized to reduce the width, the height should be adjusted. If the height is reduced, the width should be adjusted accordingly.
I am using HTML5 and CSS3. This is an attempt to create a responsive layout which works on desktop and mobile devices.
It is pretty easy to adjust height to width.
Since padding percentages are relative to parent's width (even for the height yes) you can do something like this:
.smth {
height: 0;
padding: 100% 0 0 0;
}
Represent width and height using %
DEMO
Try this,
HTML:
<div><p>content</p></div>
CSS:
div {
border: 1px solid red;
width: 35%;
padding: 40%;
box-sizing: border-box;
position: relative;
}
p {
position: absolute;
top: 0;
left: 0;
}
Using Jquery,
jQuery Code:
var width = $('#widthHeight').width();
$('#widthHeight').css('height', width);
jqueryDEMO
As you're using CSS3 you can make use of the vmin or vmax units. 1 vmin is equivalent to 1/100 the size of whichever is smallest out of height or width, whereas 1 vmax is equal to 1/100 the size of the larger value. If a user's screen had a resolution of 1000x800px, 100vmin would be equal to 800px and 100vmax would be equal to 1000px, as the height here is the smaller unit and the width is the larger unit.
In your case you can make use of it like this:
div {
height: 65vmin;
width: 100vmin;
}
Or:
div {
height: 65vmax;
width: 100vmax;
}
JSFiddle demo.
Note that you'll have to adjust these values yourself. 100vmin here will set the width to full size of the screen's height or width (whichever is smallest), and this may not be the desired effect.
There are a couple of browser issues with this approach, unfortunately. As they are new units, support is not perfect. Some browsers will not resize the container until the page is reloaded.
How about this:
FIDDLE
div
{
width: 153.8vh; /* 100/65 * 100 */
height: 65vw; /* 100/1.538 = 65 */
background: pink;
max-height: 650px;
max-width: 1000px;
margin: auto;
position: absolute;
top:0;bottom:0; /* vertical center */
left:0;right:0; /* horizontal center */
}
I've looked everywhere .
and still couldn't come up with sample code of a very "basic" idea:
A div that is taking 90% of the screen size and it is adjusting itself whenever the browser size changes (to take 90% of the relative screen)
The nested divs inside it should resize themselves as well.
Is it even possible?
EDIT:
Width 90% is not working when I try to re size the screen vertically.
Use vh attributes. It means viewport height and is a percentage. So height: 90vh would mean 90% of the viewport height. This works in most modern browsers.
Eg.
div {
height: 90vh;
}
You can forego the rest of your silly 100% stuff on the body.
If you have a header you can also do some fun things like take it into account by using the calc function in CSS.
Eg.
div {
height: calc(100vh - 50px);
}
This will give you 100% of the viewport height, minus 50px for your header.
In this scenario, the outer <div> has a width and height of 90%. The inner div> has a width of 100% of its parent. Both scale when re-sizing the window.
HTML
<div>
<div>Hello there</div>
</div>
CSS
html, body {
width: 100%;
height: 100%;
}
body > div {
width: 90%;
height: 100%;
background: green;
}
body > div > div {
width: 100%;
background: red;
}
Demo
Try before buy
I was searching for similar solution, I think here it is better to fiddle with Javascript since we are dealing with dynamic changes.
I rendered two divs, one outside the other, set Height/Width of outer div based on screen width (based on 1500px width 100px outer div. For the inner div I calculated based on percentage of the outer div.
HTML
<div class="wrapper">
<div class="box outer">
<div class="box inner"></div>
</div>
</div>
CSS
.wrapper{
/* not important just to make the box appear in center for visibility*/
display: block;
margin: 200px auto;
width: fit-content;
}
/*Only selecting background colors and making inner box adjust in the center of outer box*/
.box.outer {
background: rgb(204, 75, 25);
position: relative;
}
.box.inner {
background: green;
position: absolute;
top:50%; left:50%; transform: translate(-50%, -50%);
}
Javascript
document.addEventListener("DOMContentLoaded", function (event) {
let outerBox = document.querySelector('.box.outer');
let innerBox = document.querySelector('.box.inner');
// multiplier is used to calculate width of inner div based on outer div, so they always look the same shape
let multiplier = 0.8;
function renderBox() {
//let outerbox Dimension based on window width assuming 1500px width as base
outerBox.style.height = window.innerWidth / 15 + 'px';
outerBox.style.width = outerBox.style.height;
innerBox.style.height = outerBox.offsetHeight * multiplier + 'px';
innerBox.style.width = outerBox.offsetHeight * multiplier + 'px';
}
window.addEventListener("load", function (e) {
renderBox();
})
window.addEventListener('resize', function (e) {
renderBox();
})
})
<!DOCTYPE html>
<html>
<head>
<style>
div {
padding: 20px;
resize: both;
overflow: auto;
}
img{
height: 100%;
width: 100%;
object-fit: contain;
}
</style>
</head>
<body>
<h1>The resize Property</h1>
<div>
<p>Let the user resize both the height and the width of this 1234567891011 div
element.
</p>
<p>To resize: Click and drag the bottom right corner of this div element.</p>
<img src="images/scenery.jpg" alt="Italian ">
</div>
<p><b>Note:</b> Internet Explorer does not support the resize property.</p>
</body>
</html>
Code Snippet:
div{height: calc(100vh - 10vmax)}
I have implemented a GoogleMapsV3 map in a twitterBootstrap basic responsive design site.
But my question is quite simple: i have:
<div id="map"></map>
and
#map{ width: 100%; height: 200px }
I'd like to be able to change the height to a form factor. Like in this "in my dreams CSS"
#map { width: 100%; height: width * 1.72 }
I have tried leaving out height, setting to auto, and all sorts of persentages - but only to make the div collapse on me always.
I have no problem writing a js-solution, but hope for a simple cleancut CSS solution, possible CSS3
If not possible, what would be the optimal way to js me out of this?? (timers, events...or the like)
Here it is. Pure CSS. You do need one extra 'container' element.
The fiddle
(tinkerbin, actually): http://tinkerbin.com/rQ71nWDT
(Tinkerbin is dead.)
The solution.
Note I'm using an 100% throughout the example. You can use whichever percentage you'd like.
Since height percentages are relative to the height of the parent element, we can't rely on it. We must rely on something else. Luckily padding is relative to the width - whether it's horizontal or vertical padding. In padding-xyz: 100%, 100% equals 100% of the box's width.
Unfortunately, padding is just that, padding. The content-box's height is 0. No problem!
Stick an absolutely positioned element, give it 100% width, 100% height and use it as your actual content box. The 100% height works because percentage heights on absolutely positioned elements are relative to the padding-box of the box their relatively positioned to.
HTML:
<div id="map_container">
<div id="map">
</div>
</div>
CSS:
#map_container {
position: relative;
width: 100%;
padding-bottom: 100%;
}
#map {
position: absolute;
width: 100%;
height: 100%;
}
You could try using vw for height.
https://developer.mozilla.org/en/docs/Web/CSS/length
Something like
div#map {
width: 100%;
height: 60vw;
}
This would set the width of the div to 60% of the viewport width. You will probably need to use calc to adjust to take padding into account …
For this, you will need to utilise JavaScript, or rely on the somewhat supported calc() CSS expression.
window.addEventListener("resize", function(e) {
var mapElement = document.getElementById("map");
mapElement.style.height = mapElement.offsetWidth * 1.72;
});
Or using CSS calc (see support here: http://caniuse.com/calc)
#map {
width: 100%;
height: calc(100vw * 1.72)
}
.video {
width: 100%;
position: relative;
padding-bottom: 56.25%; /* ratio 16/9 */
}
.video iframe {
border: none;
position: absolute;
width: 100%;
height: 100%;
}
16:9
padding-bottom = 9/16 * 100 = 56.25
Try viewports
You can use the width data and calculate the height accordingly
This example is for an 150x200px image
width: calc(100vw / 2 - 30px);
height: calc((100vw/2 - 30px) * 1.34);
I need to do "fluid" rectangles not squares.... so THANKS to JOPL .... didn't take but a minute....
#map_container {
position: relative;
width: 100%;
padding-bottom: 75%;
}
#map {
position:absolute;
width:100%;
height:100%;
}
You can use CSS like this to crop the image to a certain ratio and then using object-fit to center the image as you want.
CSS:
.ratio-crop {
aspect-ratio: 1.72 / 1; //using the example size in the question
object-fit: cover;
}
HTML:
<img src="/images.jpg" class="ratio-crop">
You can set its before and after to force a constant width-to-height ratio
HTML:
<div class="squared"></div>
CSS:
.squared {
background: #333;
width: 300px;
}
.squared::before {
content: '';
padding-top: 100%;
float: left;
}
.squared::after {
content: '';
display: block;
clear: both;
}
Solution with Jquery
$(window).resize(function () {
var width = $("#map").width();
$("#map").height(width * 1.72);
});
I've made similar thing with YouTube's IFRAME where the iframe is inside a grid that always changed based on portrait/landscape so this code worked for:
So the code for this question is:
// Layout resize
let height = window.innerHeight;
let width = window.document.getElementById('player').parentNode.clientWidth;
height = width / 1.77;
<div id="player"></div>
... etc ..
function onYouTubeIframeAPIReady() {
// Layout resize
let height = window.innerHeight;
let width = window.document.getElementById('player').parentNode.clientWidth;
height = width / 1.77;
player = new YT.Player('player', {
width: '100%',
height: height,
videoId: currentVideoId,
playerVars: {
'autoplay': 0,
'loop': 0,
'mute': 0,
'controls': 0,
'enablejsapi': 1,
'playsinline': 0,
'rel': 0,
'widget_referrer': 'http://my domain ...'
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange,
'onError': onError
}
});
}
Let me describe the JS solution as a separate answer:
function handleResize()
{
var mapElement = document.getElementById("map");
mapElement.style.height = (mapElement.offsetWidth * 1.72) + "px";
}
<div id="map" onresize="handleResize()">...</div>
(or register the event listener dynamically).
mapElement.style.width * 1.72 will not work, since it requires that the width be set explicitly on the element, either using the width DOM attribute or in the inline style's width CSS property.
#map {
width: 100%;
height: 100vw * 1.72
}