How to maintain proportion on resize of a layout with absolute positioned elements - css

I've been handed a bunch of pages to code up with weird irregular layouts. Below is an example of what I need to create.
The key points about this are;
The elements need to be positioned pixel perfect as per the mockups.
Upon window resize, all elements and the positions need to size down/up
proportionately.
The size of the container needs to resize proportionately also, because there will be more content under the layout.
Considering each element needs to have specific positioning, it's obvious to use absolute positioning. I also note that because the layout needs to stay proportionate, positioning needs to be done in percentages.
For images I can set the widths to be a percentage and height auto. And elements can be positioned with a percentage along the x axis.
But the problem arises when I need to position from the top.
If I declare an element to be say 20% from the top, this positioning won't change proportionately when I resize the page. Also, the containing block will need to have a declared height.
The only way I can see this working is with some javaScript trickery.
But this seems fussy for a seemingly simple layout. And it's not advisable to rely on javaScript to maintain a layout.
There must be a better solution, I've seen irregular layouts like this often.
I've looked into Flexbox, but I can't think of how it can help me in this situation.
How would you tackle this layout?

You can wrap everything in a wrapper that uses the "padding-bottom trick" to maintain its ratio based on its width. Because the height of the parent element is now dependent on the width of the document, all percentage values you give to top and bottom properties of child elements will be affected by the width of the page, instead of the height.
main {
position: relative;
width: 100%;
height: 0;
padding-bottom: 120%;
}
div {
background: red;
position: absolute;
}
.one {
width: 40%;
height: 40%;
top: 10%;
left: 40%;
}
.two {
width: 50%;
height: 20%;
top: 55%;
left: 15%;
}
.three {
width: 20%;
height: 30%;
top: 60%;
left: 70%;
}
<main>
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
</main>

Try using this trick to scale your container proportionally
<div class="container">
<div class="container-inner-wrap">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
.container {
position: relative;
display: inline-block;
width: 75%; // Choose the width you want.
}
.container:after {
padding-top: [$height / $width * 100] %;
content: '';
display: block;
}
.container-inner-wrap {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
Where $height and $width are numbers - the value of the height and width you want your container to be. The real value you should put in there is what you get when you divide the ideal height by the width and multiply that by 100% (the unit is going to be %). What you get then is the aspect ratio of your container, and it will stay that size and shape no matter your browser size.
You can use that on all your boxes too, just make sure that you have that inner wrap that's absolutely positioned just inside. If I was building this layout, I'd use this trick for sure.
Here's an example of someone else using this: http://wellcaffeinated.net/articles/2012/12/10/very-simple-css-only-proportional-resizing-of-elements/

Related

Scale dynamic image with different widths and heights

I have image in the header and populate its source from the database, so it has different width and height. Image dimensions could be max 2000x2000px. I'm trying to scale it but when it's very large e.g more than 1000px it's very big and it's not looking good.
This is what I currently have.
#image {
position: absolute;
display: block;
top: 20px;
left: 20px;
height: 50px;
}
<div id="wrapper">
<img src="some-dynamic-url" id="image">
</div>
I've also tried with background-size: cover but it's not stretched and how to preserve the aspect ratio and set max-width and max-height not to be so big?
Updated. My current code is the following:
#image {
display: block;
top: 20px;
left: 20px;
width: 100%;
max-width: 170px;
}
<div id="wrapper">
<img src="some-dynamic-url" id="image">
</div>
Will the height always be 50px? If not, you should remove that from your CSS and instead use height: auto;.
Also, if it starts to not look so great at 1000px by 1000px, maybe set width: 1000px; and max-width: 85%; to keep it at that width and make it responsive on smaller screens. You can adjust the max-width value to your liking or remove it.
So, the CSS would change to:
#image {
position: absolute;
display: block;
top: 20px;
left: 20px;
width: 1000px;
max-width: 85%; /* adjust as needed or remove */
height: auto;
}
Here's an example.
If I'm understanding correctly, you have a header container area where various images get populated, and sometimes the images are too big for the container and not looking good. (A screenshot would be helpful if my summary is wrong.)
The trick here is to set the image width to 100%, then set a max-width to either the image or the header container. (I picked 1200px for this example.) That ensures that your image will fill up all of the space, but not go over.
NOTE: this will cause images with widths smaller than 1200px to be stretched to fit, and may not look good either and would require some more coding to fix.
#image {
position: absolute;
display: block;
top: 20px;
left: 20px;
width: 100%;
max-width: 1200px;
}
<div id="wrapper">
<img src="https://upload.wikimedia.org/wikipedia/commons/c/cc/ESC_large_ISS022_ISS022-E-11387-edit_01.JPG" id="image">
</div>
However, if you're looking for a work-around for images that are smaller than 2000px wide, I'd suggest something like centering them with a colored background, or perhaps tiling them. Those solutions will be good for some content, and ugly for others - it depends what you images are like and how the site looks. But those are some ideas.
You may want to use the simple trick to automatically fit size with:
img { max-width: 1200px; height: auto;}
I guess 50px for height is not a must since you thought using "cover" in backround property. Also if you wish this sort of behavior from your image, you can add "object-fit: cover;".
Read more here: https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
EDIT
You can also use that version of the "trick":
img { max-height: 100px; width: auto; }
Note: Using files that big for logo is not recomand. If you got access tto database you should consider save a copy to more light version with less pixels.

CSS banner image, doesn't scale beyond the parent element

I'm trying to style a typcial banner image for a site, so that for narrower viewports the vertical height is maintained and the image effectively stays the same size by going beyond the parent element horizontally. (I think this is fairly typical banner image behaviour - but feel free to correct me if I'm wrong).
(browser target is ie10 and up). The below incorrectly keeps the image ratio and at 100% width so that if fails to match the height of the parent.
The current html is just an img inside a div tag
<div class="banner">
<img class="img-fluid" src="somepic.jpg" />
</div>
Where the css classes used are:
.banner {
content: "";
position: absolute;
width: 100%;
top: 0;
left: 0;
height: 780px;
}
and img-fluid is a bootstrap(4) class with
img-fluid {
max-width: 100%;
height: auto;
}
Use a background-image instead, there are a couple interesting behaviours that can be used to achieve different results.
Here's my take:
.banner {
content: "";
position: absolute;
width: 100%;
top: 0;
left: 0;
height: 780px;
background-image:url('somepic.jpg');
background-size:cover;
}
The key here is background-size:cover;, it will make sure the image stretches to cover the full width and height while keeping its ratio. That means on very wide screens, it will be made larger, cutting some height. But on thinner resolutions you'll get the desired output.

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>

set div width as a percentage of height

I am trying to set the width of the .full_height_div element using pure css, based on its height. It has to be width-relative-to-height, and not height-relative-to-width. The reason for this is that the parent container (.set_rectangle_height) is already a div with height relative to the page width. Obviously, as the page is resized the divs on the page will resize, so i cannot set a fixed width in px for the .full_height_div child.
So .rectangle and .set_rectangle_height make up the parent container which has a width as a percentage of the page and a height relative to this width. See here for an explanation for this method.
But the problem is that then I want to place a div inside the parent with height: 100% and width relative to this height. The aim is then that I will be able to alter the browser window size and everything will keep its aspect ratio.
here is my failed attempt:
.rectangle
{
position: relative;
width: 30%;/*the outermost div is always a % of the page
width, even while resizing*/
display:inline-block;
background-color: green;
}
.set_rectangle_height
{
padding-bottom: 30%;/*this sets the height of the outermost div
to a ratio of 1:3*/
position: relative;
float: left;
width: 100%;
height: 100%;
}
.full_height_div/*this is the div that i want to have a width relative
to its height*/
{
height: 100%;
width: 20px;/*i will delete this once .square_set_width is working*/
position: absolute;
background-color: red;
}
.square_set_width
{
display: inline-block;
padding-left: 100%; /*i want to use something like this line to set
the width of this div to be equal to .full_height_div's height - ie a 1:1 aspect
ratio, but padding-left does not work :( */
position: relative;
height: 100%;
background-color: blue;
}
<div class='rectangle'>
<div class='set_rectangle_height'>
<div class='full_height_div'>
<div class='square_set_width'></div>
</div>
</div>
</div>
So, this is what the above incorrect markup looks like:
And this is what i want it to look like:
I know I could find the blue square percentage height in javascript, then set the width to be equal to this height, but it would be really handy if there is a pure css fix for what I am trying to do. I will be using this structure a lot and I don't really want to go writing code to resize all the divs on my page.
you have to use javascript for that. If I understood you, you want a perfect blue square. Use
var height = $('.square_set_width').height();
$('.square_set_width').css('width',height);
here is a jsfiddle: http://jsfiddle.net/a8kxu/
Edit: instead of doing padding-bottom: 30% do height: 70% instead. Here is another fiddle: http://jsfiddle.net/a8kxu/1/
Edit #2: Sorry, but you cant use css to do this. Its not powerful enough
If i understand you correctly
you can do
#divID {
width: 75%;
margin-left: auto; // this is used to center the container
margin-right: auto;// this as well
}

Trying to set JScrollPane height to 100% without stretching container?

I have a middle container that takes up whatever vertical space is left on the screen. In it, I placed a Jquery scroller that is currently set to 200px:
.scroll-pane
{
width: 100%;
height: 200px;
overflow: auto;
}
.horizontal-only
{
height: auto;
max-height: 100%;
}
However, if I set .scroll-pane height to 100%, it just removes the scrollbar and stretches the whole page.
See JsFiddle here
How can I stop this? Thanks!
Here is my solution to this problem (jsfiddle). It uses markup like this:
<div id="top">...</div>
<div id="wrapper">
<div id="middle">...</div>
</div>
<div id="bottom">...</div>
The top and bottom divs are position absolutely at the top and bottom, with a width of 100%. The wrapper div has height: 100%, box-sizing: border-box, and top and bottom padding equal to the height of the top and bottom divs, respectively. This causes it to fill the viewport but have padding underneath the top and bottom divs. The middle div has a height of 100% so it fills the content box of the wrapper (i.e., 100% minus the top and bottom paddings). It has position: relative, which leaves you free to use height: 100% on both interior boxes.
Lastly, middleleft is positioned absolutely and middleright has a left margin equal to its width, which causes it to fill the remaining horizontal space.
height: 100% never works like you want it to. The CSS specifications dictate that it must equal the height of the browser window, or the closest parent block-level element with an absolute height specified. That means that this code will should not work as expected:
<!DOCTYPE html>
<html>
<head>
<title>Want the body to fill the page? Too bad!</title>
<style type="text/css">
html, body {
height: 100%;
}
.page {
padding-top: 50px;
box-sizing: border-box;
height: 100%;
}
.header {
margin-top: -50px;
height: 50px;
}
.body {
height: 100%;
background: gray;
}
</style>
</head>
<body>
<div class="page">
<div class="header">
<h1>Too bad!</h1>
</div>
<div class="body">
<p>Hello cruel world...</p>
</div>
</div>
</body>
</html>
However, that works fine in Chrome. Why? I can only assume that Google decided to specifically go against web standards because in this case, the standards make no sense. Why would I want something to be the exact height of the browser window? The only time is a <div> wrapping the whole page; in this case a simple "height is relative to the parent block" rule works just fine without breaking expectations elsewhere.
There is a way around this, though. At least, that's what I wanted to say before I tried this in Firefox too. Another way to get height: 100% (with some restrictions) is with position: absolute. However, it would seem that Firefox isn't respecting position: relative on a display: table-cell element - probably those pesky standards again. Here's the code for this technique anyway, if you are interested:
#wrapper > div > #middleleft {
position: relative;
}
.scroll-pane {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
So what can you do? Well, unfortunately, I don't yet know the answer to that. A kludgy solution would be to have Javascript set the height to an absolute pixel value, and attach an event to window resizing in order to update that height. I'll get back to you if I find a better way.
I'm not sure exactly what your trying to do, but another method would be to set body height to 100%, then set scrollpane to "height: auto". Then for the "top" and "bottom" div's used fixed positioning, plus margin equal to top/bottom height.
body {
height: 100%;
}
.top {
position: fixed;
top: 0;
height: 100px;
}
.middle {
height: auto;
margin: 100px auto;
}
.bottom {
position: fixed;
bottom: 0;
height: 100px;
}
<div class="top">content</div>
<div class="middle">content</div>
<div class="bottom">content</div>
Try that...

Resources