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

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

Related

Making an image width:100% inside a inline-block element

If I have an image on a page with width set to 100% in css it is as wide as the browser. Fine. However, if I make a containing div have display:inline-block, then the image is no longer set to have a width:100%. Instead, it just shows as the actual width of the image:
img {width:100%;}
<img src="http://www.gannett-cdn.com/-mm-/0c9109c71ea0524d9fe840f91fabd67bb94a26a9/r=537&c=0-0-534-712/local/-/media/USATODAY/USATODAY/2013/05/30/1369920769000-grumpycat-1305300933_3_4.jpg"/>
<div style="display:inline-block;">
<img src="http://www.gannett-cdn.com/-mm-/0c9109c71ea0524d9fe840f91fabd67bb94a26a9/r=537&c=0-0-534-712/local/-/media/USATODAY/USATODAY/2013/05/30/1369920769000-grumpycat-1305300933_3_4.jpg"/>
</div>
So, basically, the inline-block containing div wants to be as wide as its contents, and the width:100% on the image wants to be as wide as the containing element, so it seems they are both confused and just defaulting to the width of the image. I know I can set the width of the containing div to be 100% and have the desired outcome, but for what I am actually doing, that is not an option. Is there any way to force the img to be 100% width with only css on the image itself? I guess I am basically trying to set a class on a parent of an element, which I do not think is possible... Ideas?
This is because a percentage value on width is relative to the width of the box's containing block. While a block-level container (<div> element, for instance) takes the entire width of its containing block, an inline-level element doesn't.
Therefore you have to specify the width of the wrapper <div> explicitly. As a thumb rule, when you say 100% you should ask yourself 100% of what?
img { width:100%; }
div { display:inline-block; width: 100%; }
<img src="http://www.gannett-cdn.com/-mm-/0c9109c71ea0524d9fe840f91fabd67bb94a26a9/r=537&c=0-0-534-712/local/-/media/USATODAY/USATODAY/2013/05/30/1369920769000-grumpycat-1305300933_3_4.jpg"/>
<div>
<img src="http://www.gannett-cdn.com/-mm-/0c9109c71ea0524d9fe840f91fabd67bb94a26a9/r=537&c=0-0-534-712/local/-/media/USATODAY/USATODAY/2013/05/30/1369920769000-grumpycat-1305300933_3_4.jpg"/>
</div>
Alternatively, in cases where you want to set the width of elements as the width of the viewport/window, you could use viewport percentage units instead. For instance:
img { width: 100vw; } /* 1vw = 1/100 of the width of the viewport */
Demo:
img { width: 100vw; }
<img src="http://www.gannett-cdn.com/-mm-/0c9109c71ea0524d9fe840f91fabd67bb94a26a9/r=537&c=0-0-534-712/local/-/media/USATODAY/USATODAY/2013/05/30/1369920769000-grumpycat-1305300933_3_4.jpg"/>
<div>
<img src="http://www.gannett-cdn.com/-mm-/0c9109c71ea0524d9fe840f91fabd67bb94a26a9/r=537&c=0-0-534-712/local/-/media/USATODAY/USATODAY/2013/05/30/1369920769000-grumpycat-1305300933_3_4.jpg"/>
</div>
I dont think this will help your problem , but technically you could do it by giving it position:absolute;
img {
width:100%;
}
div img {
position:absolute;
margin:0 auto;
width:100% !important;
}
http://jsfiddle.net/kjf8s3rq/
The problem is that you are trying to use dislay-inline in a way contrary to its intended use. If you want the image to take up the full width of the window, then clearly its container must also take up the full width. Which means you want your div to behave like a block element. So the solution is either to do just that and leave the div as display:block (its default value to start with), or at the very least you must set it's width to width:100%. Afterall, if you want to take up the full width of the screen then you want it to be a block.
Inline-block elements have to have their width set, either by specifying a width in the CSS, or by letting them take up as much width as they need to hold their content. In your case the image has its natural size, and your surrounding inline-block div is therefore taking up just that size and no more.
Setting width:100% on the image doesn't change that; that just tells it to take up the full with of its container, not the whole window. But your containing div is already the natural size of the image.

How to keep the w/h:auto resizable ability of an img inside figure/img/figcaption

Keeping the w/h:auto resizable ability of an img when its parent is set to display:table and the parent's w/h is not 100%? It seems obvious that if the parent's w/h is not set then its child's w/h:auto makes not much sense. My point is, I want to keep the "resizable ability" of an img if it is inside figure/img/figcaption. Description of the problem:
Big images in a gallery we may want to resize to fit the window size if bigger. If it is just an image it can be done easily setting the image's w/h to auto (and maxw/maxh to 100%), with adding margin:auto we get it even nicely centered. But how to achieve the same with figure/img/figcaption altogether? As we want the figcaption's width to match the width of the image dynamically on the fly (not in px) we need to set figcaption display:table-caption (plus caption-side:bottom) and figure display:table. But once we set the figure display:table and its w/h is not set (or is set to auto, otherwise figcaption width will not match the img's), image w/h:auto don't work any more (not much surprisingly) and we get a not desirable 100% of w/h of the img (will not fit into the window if bigger). Is there any CSS only solution how to keep w/h:auto of the img or somehow achieve the same resizable ability if it is inside figure/img/figcaption?
There are many great approaches out there of how to center or resize elements or images, for example here <codepen.io/shshaw/full/gEiDt> or here <codepen.io/dimsemenov/pen/jhsJL>, but these and many more elsewhere don't work with a set of figure/img/figcaption (or I was unable to make it work). I am troubling myslef with it literally for days long with no clear answer.
In other words, what I need: A figure/img/figcaption set is centered altogether, they will resize if the image is bigger than window size, figcaption must match the width of the image width. All should be done with CSS and without setting anything in px.
So <img> and <figcaption> all go inside a <figure> element. All three are block elements.
You would just set the height and width of your <figure> element, then add a margin auto like you said.
Then set in your css:
img {
width: 100%;
height: auto;
}
figcaption {
text-align: center;
width:100%;
}
And now your image and your caption will always be the width of the figure element, the text will always be centered under the image, and the larger element will always be centered on the page.
EDIT: Adding 100% as a width or height to something means "100% of the parent element". So if you set a width/height for your figure element, the elements inside can be 100% and they won't break the element. Again, all three are block elements already, so you don't need to re-declare them as display: table-caption or whatever. Just use the strength of the block element as it is.
EDIT 2: OKAY. Here's what you need:
Set the figure to a specific height and width in CSS.
Then set the img and figure inside your fig caption to: width: 100%; height: auto;.
Your html looks like this:
<body>
<figure>
<img src="">
<figcaption>Some Text</figcaption>
</figure>
</body>
Now you need a media query in your CSS to handle the size of <figure>
#media screen and (max-width: 600px) {
figure {
width: /*Whatever width you want*/
height: /*Whatever height oyu want*/
}
}
Then repeat your media query for different break points.
If you still think I'm wrong, make a codepen or fiddle with an example and I'll help you from there.
EDIT 3
Here is a JSFiddle demonstrating that you can make a responsive image and element using relative measurements in % and maintaining the image centered to the things around it.
http://jsfiddle.net/o2rv4t9h/1/

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

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?

css resize div proportionally, similar to image resize

is it possible to have a div (or other element) resize its height in relation to its width (or the other way around) using CSS? basically, to get it to behave the way an image with a percentage width resizes proportionally as the browser window is resized?
If you want to set a width or height relative to a .parent element and you know the aspect ratio that needs to be maintained, you can do something like this:
.parent{
width: 150px;
}
.child{
width: 100%;
padding-top: 50%; /* outer height will be 75px (150px*0.5) */
}
Note that you are relying on having a height (or width) of 0 and defining it based on the padding only. So, if you want to add any content you will probably need to wrap it within an absolutely positioned div within .child. See this fiddle for an example
Look at this related question. In short: No, it's not possible using only CSS

Seeking CSS Browser compatibility information for setting width using left and right

Here's a question that's been haunting me for a year now. The root question is how do I set the size of an element relative to its parent so that it is inset by N pixels from every edge? Setting the width would be nice, but you don't know the width of the parent, and you want the elements to resize with the window. (You don't want to use percents because you need a specific number of pixels.)
Edit
I also need to prevent the content (or lack of content) from stretching or shrinking both elements. First answer I got was to use padding on the parent, which would work great. I want the parent to be exactly 25% wide, and exactly the same height as the browser client area, without the child being able to push it and get a scroll bar.
/Edit
I tried solving this problem using {top:Npx;left:Npx;bottom:Npx;right:Npx;} but it only works in certain browsers.
I could potentially write some javascript with jquery to fix all elements with every page resize, but I'm not real happy with that solution. (What if I want the top offset by 10px but the bottom only 5px? It gets complicated.)
What I'd like to know is either how to solve this in a cross-browser way, or some list of browsers which allow the easy CSS solution. Maybe someone out there has a trick that makes this easy.
The The CSS Box model might provide insight for you, but my guess is that you're not going to achieve pixel-perfect layout with CSS alone.
If I understand correctly, you want the parent to be 25% wide and exactly the height of the browser display area. Then you want the child to be 25% - 2n pixels wide and 100%-2n pixels in height with n pixels surrounding the child. No current CSS specification includes support these types of calculations (although IE5, IE6, and IE7 have non-standard support for CSS expressions and IE8 is dropping support for CSS expressions in IE8-standards mode).
You can force the parent to 100% of the browser area and 25% wide, but you cannot stretch the child's height to pixel perfection with this...
<style type="text/css">
html { height: 100%; }
body { font: normal 11px verdana; height: 100%; }
#one { background-color:gray; float:left; height:100%; padding:5px; width:25%; }
#two { height: 100%; background-color:pink;}
</style>
</head>
<body>
<div id="one">
<div id="two">
<p>content ... content ... content</p>
</div>
</div>
...but a horizontal scrollbar will appear. Also, if the content is squeezed, the parent background will not extend past 100%. This is perhaps the padding example you presented in the question itself.
You can achieve the illusion that you're seeking through images and additional divs, but CSS alone, I don't believe, can achieve pixel perfection with that height requirement in place.
If you are only concerned with horizontal spacing, then you can make all child block elements within a parent block element "inset" by a certain amount by giving the parent element padding. You can make a single child block element within a parent block element "inset" by giving the element margins. If you use the latter approach, you may need to set a border or slight padding on the parent element to prevent margin collapsing.
If you are concerned with vertical spacing as well, then you need to use positioning. The parent element needs to be positioned; if you don't want to move it anywhere, then use position: relative and don't bother setting top or left; it will remain where it is. Then you use absolute positioning on the child element, and set top, right, bottom and left relative to the edges of the parent element.
For example:
#outer {
width: 10em;
height: 10em;
background: red;
position: relative;
}
#inner {
background: white;
position: absolute;
top: 1em;
left: 1em;
right: 1em;
bottom: 1em;
}
If you want to avoid content from expanding the width of an element, then you should use the overflow property, for example, overflow: auto.
Simply apply some padding to the parent element, and no width on the child element. Assuming they're both display:block, that should work fine.
Or go the other way around: set the margin of the child-element.
Floatutorial is a great resource for stuff like this.
Try this:
.parent {padding:Npx; display:block;}
.child {width:100%; display:block;}
It should have an Npx space on all sides, stretching to fill the parent element.
EDIT:
Of course, on the parent, you could also use
{padding-top:Mpx; padding-bottom:Npx; padding-right:Xpx; padding-left:Ypx;}

Resources