Working with % in CSS: position:absolute and image size - css

I am trying to design a fluid layout with %, featuring books at 50% of the window height, with a quarter of the next book just visible, tempting one to scroll down.
Resizing the window should not change the layout, so the image size of the books, the margins, etc. should be given in %.
However, setting .books {position: absolute} for the containing divs, the size of the contained image shrinks to thumbnail size, although the images themselves are fairly large...
How does % as unit work? I figured 100% always is 100% of its containing element. Why would position: absolute change this?
A second question, even when working with %, changing only the window width changes the vertical layout. I had assumed that a the vertical and horizontal directions are independent.
Here are some code snippets.
<div id="container">
<div class="books">
<img src="..." />
</div>
<div class="books">
<img src="..." />
</div>
<div class="books">
<img src="..." />
</div>
</div>
#container {
height: 200%;
}
.books {
height: 25%; /* =50% of window height */
}
EDIT: I found the culprit: I assigned a top margin in %, but all (top bottom left right) margin values are defined as % of the width of the parent... Strange.

add this to your css
.books img {width:100%; height:100%}

To answer your question about position: absolute, The element is positioned relative to its first positioned (not static) ancestor element, therefore the % change of the containing div will affect the image size. Source: click here
From experience you'll end up running into a few issues with various browsers using % width and height. Fixing sizes and supplying multiple style sheets based on the detected device being used is probably the better way to go.

You'll need to specify the heights of all parents, right up to html i.e.
html, body{
height: 100%;
}
#container {
height: 200%;
}
.books{
height: 25%; /* =50% of window height */
}
.books img{
height: 100%;
}
If you change to position: absolute, then the parent will be the next positional parent, which you can specify by making it position: relative (or position: absolute).
The above code will mean that resizing the window will change the layout. But you could set a specific size at some point in the chain, or do it with javascript?

Related

Why does max-width and width display a completely different result?

I am working on my CSS skills and by watching Kevin Powell's video "How to use CSS object-fit to control your images", I couldn't understand why the use of either max-width or width would completely alter the result.
Here's the HTML:
<div class="card">
<img class="card__image" src="//unsplash.it/500" alt="">
</div>
And here is the first CSS code (pay attention to tard .card__image 's width)
.card{
background: lightgreen;
width: 350px;
padding: 3rem;
}
.card__image{
width: 100%;
height: 150px;
}
On the second version of the CSS code, we switch .card__image's width to "max-width".
Now I don't understand why when we use "width", the image is stretched out and takes the entire width of the parent element it's inside of, but when we use "max-width",it's as if it no longer focuses on the parent element but on the image itself. It proportionally fixes the image's dimensions so the image would appear in full/no stretch, inside the parent element.
In result, with "width", the image is stretched out and takes the entire parent element's space. With "max-width", the image is not stretched out and simply takes whichever amount of space it needs to.
How come ?
The difference between width: 100% and max-width:100% is that: First,
width define the width of the specific element while max-width define the
maximum size the element is allow to have link

Is it possible to calculate the Viewport Width (vw) without scrollbar? [duplicate]

This question already has answers here:
100vw causing horizontal overflow, but only if more than one?
(8 answers)
Closed 4 months ago.
As mentioned in the title, is it possible to calculate the vw without the scrollbars in css only?
For example, my screen has a width of 1920px. vw returns 1920px, great. But my actual body width is only something like 1903px.
Is there a way for me to retrieve the 1903px value with css only (not only for direct children of the body), or do I absolutely need JavaScript for this?
One way to do this is with calc. As far as i know, 100% is the width including scrollbars. So if you do:
body {
width: calc(100vw - (100vw - 100%));
}
You get the 100vw minus the width of the scrollbar.
You can do this with height as well, if you want a square that's 50% of the viewport for example (minus 50% of the scollbar width)
.box {
width: calc(50vw - ((100vw - 100%)/2))
height: 0
padding-bottom: calc(50vw - ((100vw - 100%)/2))
}
I do this by adding a line of javascript to define a CSS variable once the document has loaded:
document.documentElement.style.setProperty('--scrollbar-width', (window.innerWidth - document.documentElement.clientWidth) + "px");
then in the CSS you can use var(--scrollbar-width) to make any adjustments you need for different browsers with/without scrollbars of different widths. You can do something similar for the horizontal scrollbar, if needed, replacing the innerWidth with innerHeight and clientWidth with clientHeight.
COPY & PASTE solution
Here is an easy drop-in solution based on user11990065's answer to set a css variable --scrollbar-width and keep it updated on resizes.
It also gets calculated on DOMContentLoaded and load events so that you don't have to worry about size changes during the initial rendering phase.
You can just copy and paste it to your code as it is vanilla JS (or wrap it in a 'script' tag and paste it directly into your HTML code:
function _calculateScrollbarWidth() {
document.documentElement.style.setProperty('--scrollbar-width', (window.innerWidth - document.documentElement.clientWidth) + "px");
}
// recalculate on resize
window.addEventListener('resize', _calculateScrollbarWidth, false);
// recalculate on dom load
document.addEventListener('DOMContentLoaded', _calculateScrollbarWidth, false);
// recalculate on load (assets loaded as well)
window.addEventListener('load', _calculateScrollbarWidth);
If you have dynamic height changes in your page that might show / hide the scrollbar, you might want to look into Detect Document Height Change with which you can trigger the recalculation also on height changes.
As the value is calculated with JS and set to a fixed value you can use it in calc operations in your CSS, like so:
.full-width {
width: calc(100vw - var(--scrollbar-width));
}
This will give .full-width exactly the available width.
According to the specs, the viewport relative length units do not take scrollbars into account (and in fact, assume that they don't exist).
So whatever your intended behavior is, you cannot take scrollbars into account when using these units.
body { overflow: overlay; }
If you don't want to overcomplicate things, this might be sufficient in certain situations. At least it fixed my issues well enough, since there was enough whitespace between the content and the viewport edges (Windows scrollbar would overlap your 20-ish most right pixels).
Webkit browsers exclude the scrollbars, other include them in the returned width.
This may of course lead to problems: for instance if you have dynamically generated content with ajax that add height dynamically, Safari might switch from a layout to another during page visualization...
Ok, it doesn't happen often, but it's something to be aware about.
On mobile, less problems, cause scrollbars are generally not showed.
That's said, if your problem is calculate exactly the viewport width without scrollbars in all browser, as far as i know, a good method is this:
width = $('body').innerWidth();
having previously set:
body {
margin:0;
}
100vw = width of the screen with scrollbar
100% = width of the screen without scrollbar
It is always preferable to use calc(100% - 50px) while measuring the screen width. Even on windows browsers where scrollbar is visible directly, return the screen width differently when compare with macOS browsers.
It's possible just very "ugly" looking.
First you need to have this script running to get the scrollbar width into a css variable:
document.documentElement.style.setProperty('--scrollbar-width', (window.innerWidth - document.documentElement.clientWidth) + "px");
Now for example if you want "real" 80vw do this:
calc(0.8 * (100vw - var(--scrollbar-width)));
"real" 40vw
calc(0.4 * (100vw - var(--scrollbar-width)));
As long as you're not expecting any actual horizontal scroll, you could use this:
body {
overflow-x: hidden;
}
Which will then just hide the tiny amount of horizontal scroll caused by the auto scrolling Y.
I came across this question while looking for an answer for my case.
I wanted to use WordPress's solution to center a div on the viewport with the viewport's width just like .alignfull would normally.
Situation:
<html>
<body>
<div class="main">
<div class="continer">
<div class="row">
<div class="col-12">
<article>
<div class="content">
<div class="alignfull-or-alignwide">
<p>The content.</p>
</div>
</div>
</article>
</div>
</div>
</div>
</div>
</body>
</html>
My solution:
html {
width: 100vw;
overflow-x: hidden;
}
.alignfull-or-wide {
margin-right: calc(50% - 50vw);
margin-left: calc(50% - 50vw);
width: 100vw;
max-width: 100vw; // change this for wide or w/e.
}
This solved my problem by making the root of the document as wide as the viewport. With this, you essentially ignore the width of any scrollbar.
By setting to 100vw we eliminate the width of the scrollbar on any platform.
By setting the overflow parameter, we prevent any content from being rendered outside of the viewport.
By setting margins, we center the left side of the div to it's relative positioned parent. This usually is the center of the viewport too.
Then, the negative margin pulls it to the left side of the viewport.
By doing the same on the right we create the illusion of the div being centered on the page.
Also something to watch out for: scrollbar-width on csswg.
The only way I found it to work without messing your code with "calc"
is to make the container element size to 100vw; Adding a wrapper around the container for overflow-x; This will make the container to be fullwidth like if the scrollbar was over the content.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html{ overflow-y: scroll; }
html, body{ padding:0; margin: 0;}
#wrapper{ overflow-x: hidden; }
.row{ width: 100vw; }
.row:after{ clear: both; content: ''; display: block; overflow: hidden; }
.row-left{ background: blue; float: left; height: 40vh; width: 50vw; }
.row-right{ background: red; float: right; height: 40vh; width: 50vw; }
</style>
</head>
<body>
<div id="wrapper">
<div class="row">
<div class="row-left"></div>
<div class="row-right"></div>
</div>
</div>
</body>
</html>
The vw unit doesn't take the overflow-y scrollbar into account when overflow-y is set to auto.
Change it to overflow-y: scroll; and the vw unit will be the viewport with the scrollbar. Then you can subtract the scrollbar size from the vw value using calc(). You can also define the scrollbar width, so it will be browser-independent.
Only downside to take into account. If the content fits into the screen, the scrollbar is shown anyway. Possible solution is to change from auto to scroll in javascript.
No, there's no way to calculate the vw without the scrollbars in CSS.
However, there's a way to solve the 100vw ruined by the scrollbar on Windows issue. You have to create a full-width element, in this case row--full-width, that beelds out of a Flex container. This solution works on both Mac and Windows:
HTML:
<section>
<div class="container">
<div class="row--full-width"></div>
<div class="row">
<div class="card">
</div>
<div class="card">
</div>
</div>
</div>
</section>
Example: https://jsfiddle.net/ecmv6ho1/show
Code: https://jsfiddle.net/ecmv6ho1/
As you can see in the example above, the row--full-width element bleeds out of the container, and it aligns with the header even when there's a scrollbar.
Tested on Edge 18 (Win), Edge 88 (Win/Mac), and Chrome 88 (Win/Mac).
The easiest way is set the html & body to 100vw:
html, body{ width:100vw; overflow-x: hidden; overflow-y: auto; margin: 0; }
The only problem is the right-most will be cut a little if scrollbar is shown.
If the case were something similar to a slider:
As posted in many answers, width 100% doesn't take into account the scrollbar, while 100vw does. In the case of having many elements that need to take the width of the window and that are nested inside a container already with 100% window width (or whose natural block width would be such), you can use:
Display flex for container
Flex: 0 0 100% for child elements
It's not my solution, but helps me create dropdown fullwidth menu with absolute in relative element in not fullwith span.
We should get scroll with in css var in :root and then use it.
:root{
--scrollbar-width: calc(100vw - 100%);
}
div { margin-right: var(--scrollbar-width); }
https://codepen.io/superkoders/pen/NwWyee

float: left on class not working on figure tag

I'm a beginner with HTML5 and CSS. I've a problem in the float: left. I want to show the figures to the right of the previous one, but it isnt working.
I've tried looking into some SO questions, but haven't found the precise answer yet. It would be great if you could help
The code is located at:
http://jsfiddle.net/ECs4g/
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link
rel="stylesheet"
href="drop.css"
>
</head>
<body>
<section id="pics">
<figure
id="pic1"
class="pictures"
>
<img
alt="figure1"
src="http://b-i.forbesimg.com/kellyclay/files/2013/12/glass.jpg"
title="pic1"
>
</figure>
<figure
id="pic2"
class="pictures"
>
<img
alt="figure2"
src="http://glass-apps.org/wp-content/uploads/2013/06/google-glass1.jpg"
title="pic2"
>
</figure>
</section>
</body>
</html>
CSS:
#pics{
width:200px;
height:200px;
}
.pictures{
float: left;
}
.pictures img{
width:100%;
height:auto;
}
You assign 200px width to #pics, but that is your container. The images have no chance to be displayed next to each other. When in doubt, the browser breaks and moves the figures underneath, which is what you see right now.
To fix, set the width to the figure elements instead:
.pictures {
float: left;
width: 200px;
height: 200px;
}
Your problem lies in your width values. You tell the container #pics to be 200px width. You then tell the images to be 100% of their container. Because the #pic1 and #pic2 elements don't have a defined width, they are by default set to auto. That means your <img> elements are taking 100% width of the container element (200px).
I would suggest leaving your img tags to be 100% width, they will then take the full width of their containing element. What you must do to fix the floats, is to then also give the .pictures class a width.
Additionally, the <figure> element, as well as most elements have some default styling applied, such as margin space. You need to make sure there are no margins, padding or border space in addition to the width or your floats will break again.
For example...
http://jsfiddle.net/ECs4g/2/
.pictures{
float: left;
width: 50%;
padding: 0;
margin: 0;
}
Here is a link to everything you need to know about floats: http://css-tricks.com/all-about-floats/
You're setting the img widths to 100%. Try setting it to a value under 50%, and see how that works.
In addition, be aware that many browsers have a default style for the HTML5 figure element. You'll have to deal with that extra padding/margin to make your layout work as expected.
That is because you're setting the width and height property to only 200px value.
Increase that value and your images would float to the left. You need to set the image size of a fraction of the container's size here too.
Here would be the example:
.pictures img {
width: 40%;
}
Then the image would have the 40% width of the containers width. So the trick would be to increase the container's size and decreasing the image's size and then the image would float to the left size of the container.

Positioning a content div below img only div

In a page I work on I have a div that contains an animation with changing images (with CSS) and below it is a wrapper div for the content, like that:
<div id="animation">
<img ...>
...
<img ...>
</div>
<div id="content">
Some content
</div>
I've tried different methods: floats, clear, position, but I cannot make the content div to stay where it should, below the animation div - it overlaps it. The only solutions I found to partially work are to give the first div the height of the images (they all have equal width and height), but when I do that it breaks on different resolutions, or to give the images height of 100% and apply the above, but then the images look incredibly ugly on different resolutions.
How can I achieve my goal, preferably using CSS only?
Edit: JSFiddle
Edit 2: I used this tutorial for the changing images.
the problem is that you have all the content in the top div as position:absolute. That way, the top div doesn't know how high it needs to be (i.e. it will be 0px high).
So the solution is to have one img not positioned; then the div is as high as this img and the content div will move down below it.
#cf4a img {
position: absolute;
left:0; top:0;
width: 100%;
}
#cf4a img:first-child { /* one non-positioned child */
position: static;
}
Updated fiddle

CSS Positioning, want to make content's width fixed when window is resized.

I have a div with two nested divs inside, the (float:left) one is the menu bar, and the right (float:right) should display whatever content the page has, it works fine when the window is at a maximum, but when i resize it the content is collapsed until it can no longer has any space, at which it is forced to be displayed BELOW the left menu bar, how can I make the width fixed so that the user may scroll when resized?
(css width didn't work, i alternated between floating the right content and not), here is the code:
<div style="width:100%">
<div style="float:left; background:#f5f5f5; border-right:1px solid black; height:170%; width:120px;"></div>
<div style="margin-right:2px;margin-top:15px; margin-bottom:5px; width:100%; border:1px solid #f5f5f5"></div>
</div>
I only need to have this working on Interner Explorer for now.
This should do it (container is the parent div containing that 2 divs):
.container {
width: 1024px;
display: block;
}
You may want to set a width on the containing div and set your overflow property
#containing_div {
width: 200px;
overflow: auto;
}
Also use the min-width property on the page if that makes sense, however that CSS property doesn't really work with IE6, this is usually what I do in that situation (supporting Firefox, IE7, IE6, etc)
#container {
min-width: 1000px;
_width: 1000px; /* This property is only read by IE6, which gives a fixed width */
}
Well, putting a width or min-width property is the way to go.
Now, without an example, or a link of the actual page, it's a bit tricky to answer.
Simply don't make the right div floating. Menu is already floating left of any other content. Just set a left-margin for the right div so the content in that div won't be wrapped around the floating div.
if the two divs are taking up 100% of the available width, could try to use percentage width and display: inline with a further div with a fixed min-width/width (boo IE) inside where required.
this is rather difficult without some HTML to go on
Your containing div should have a width wide enough to contain both inner div's
So if your two inner div's are 300px each and assuming you have no margin/padding on them then you should set the outer div to be 600px;
I'm a bit confused:
Fixed width means the width of a node will not change. Never.
You say you want to scroll when the screen gets too small for your content, so I think you mean the exact oposite of fixed width.
If my assumption is right, you could as mentioned before go for the percentual widths.
Watch out width the suggested "min-width" solution because it is not supported all that well.
<div id="container" style="width:100%">
<div id="primaryNav" style="float:left; width:150px; background-color: Orange">someNav</div>
<div id="content" style="margin-left: 10px; background-color: Red; overflow: auto;">
loadsOfSuperInterestingContentI'mSuperSerious<br/>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
Seriously
</div>
</div>
This should be pretty cross browser

Resources