column flex with height 0 padding trick - html

I have 2 divs that are placed on top of each other. For purposes of alignment, I am using display: flex and flex: column on the div containing these two divs. However, the first div uses the "height 0 padding" trick for videos. The problem I'm having, is that when using flex: column and change the width of the screen, the height doesn't change (and I want the height to change so that it matches the ratio for the video). What ends up happening is that the div stays the same, and the video shrinks within it and it looks ugly because there is extra background.
Plunker: https://plnkr.co/edit/TaeF5f8VufJWPU3GRZPr?p=preview
(in short, I want it such that when I change the width of the browser, the red div's height gets smaller)
CSS
/* Styles go here */
body {
height: 100%;
}
.container {
height: 80vh;
display: flex;
flex-flow: column;
}
.video {
flex: none;
height: 0;
padding-bottom: 30%;
background-color: red;
width: 80%;
}
.next-content {
flex: 1 0 auto;
width: 80%;
background-color: blue;
}
HTML:
<body>
<h1>Hello Plunker!</h1>
<div class="container">
<div class="video"></div>
<div class="next-content"></div>
</div>

Related

Adapt image to text vertically

I have a text and an image. These must be adapted to a parent, to who I define a height, for example 100px
The text have to fill what it need. It can be a simple phrase or a long paragraph, for this i can't define a fixed height.
With the remaining space, I want to put a img, but when i put it, the images take the original img height size. You can see my snippet here:
.parent{
height: 100px;
width: 100%;
padding: 10px;
display: flex;
flex-flow: column;
}
.parent img {
flex: 1 1 auto;
}
.parent .textContainer{
flex: 0 1 auto;
}
<div class="parent">
<img src="https://via.placeholder.com/250x250"/>
<div class="textContainer">Text or html here</div>
</div>
Basically, what happens is that the image takes the height that the base image has, that is, if the image is 700px high, it takes 700px high and it goes out of the div, positioning itself as if it were positioned at absolute (it isn't ).
if i understand your concern correctly, what im going to do in this case is im going to set a max width and height for the then add width: 100% in the image.. for example
<div class="parent">
<img class="image-style" src="https://via.placeholder.com/250x250"/>
<div class="textContainer">Text or html here</div>
</div>
.parent{
height: 100px;
width: calc(100% - 20px);
padding: 10px;
display: flex;
flex-flow: column;
}
.image-style{
width: 100%;
height:100%;
//add more styles if you want
}

How to have a div size adjusted to an image displayed size

I have a div with an image inside.
The div has a fixed height, lower than the image intrinsic height.
I want the div's width to be always equal to the "displayed" width of the image (which is a function of the unknown div's height and image's height/width ratio).
Here is a codepen example of what I want to do (having "shrink" and "other" divs the same width than their child image)
<div class="container">
<div class="shrink">
<img src="https://dummyimage.com/600x400/0f0/fff" />
</div>
<div class="other">
<img src="https://dummyimage.com/600x400/00f/fff" />
</div>
</div>
div { margin: 5px; }
img { max-height: 100%; }
.container {
background-color: red;
display: flex;
flex-flow: row nowrap;
width: 800px;
height: 100px;
overflow: hidden;
}
.shrink {
flex: 0 1 auto;
background-color: #88FF88;
}
.other {
flex: 0 1 auto;
background-color: #8888FF;
}
Is it possible with only HTML/CSS ie without Javascript ?
Thanks in advance.
Remove width as an attribute of your container and the div will conform to the width of its contents.
Does this work for you?

css - scroll issue with flexbox and max-height

I'm facing a strange issue that might have link with flexbox misbehaving with max-height, but so far I didn't find any pure css solution.
I made a plunker to summarize the problem. If you resize your window to reduce its height, at some point you should have a scrollbar in the first block, but if you get back to a higher height, even if there is enough space, the scrollbar won't disappear unless you put your mouse over it (which feels very bugy) : https://plnkr.co/edit/VsJ7Aw8qZdSM1iJeL7Bj?p=preview
I have a main container (in flex) containing 2 blocks (also in flex).
The main container has its height set to 100%, allowing it to resize itself following the window size.
Both children have a fixed content and an overflow-y set to auto.
The first child has a max-height in % to let more height to the second child.
The issue seems to come from this max-height rule. If you remove it, then there's no problem, but I need this max-height...
I don't want to use something like:
.max { flex: 1 1 auto; }
.all { flex: 3 1 auto; }
because it would make my first block higher than its content depending on the window size. I want the first block to have at most its content height.
So my question is: Is it an implementation issue in many browsers (maybe all, but I only tested it in Chrome, IE10 and IE11), or is something wrong in my logic ?
Thank you.
UPDATE: I used a fixed height for my content in this example, but in my project it's a list of n elements in it. So I can't really set my max-height with px value.
UPDATE2: I can't use vh in .max max-height property because it takes 100vh as 100% of viewport height (basically your browser window height). But in my context, .main is already in other containers. Those containers have already their heights defined and are smaller than my window height.
/* Styles go here */
html {
height: 100%;
}
body {
height: calc(100% - 16px);
}
.main {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
.max,
.all {
display: flex;
flex-direction: column;
width: 100%;
overflow-y: auto;
}
.max {
flex: 0 1 auto;
min-height: 103px;
max-height: 40%;
background-color: green;
}
.all {
flex: 2 1 auto;
min-height: 235px;
background-color: blue;
}
.content {
flex: 0 0 auto;
box-sizing: border-box;
height: 200px;
margin: 5px;
border: 1px dashed black;
background-color: white;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="main">
<div class="max">
<div class="content"></div>
</div>
<div class="all">
<div class="content"></div>
</div>
</div>
</body>
</html>
It is a bug, in Chrome, a test in FF and Edge, it works fine.
Since you use full viewport height, change the max-height: 40%; to max-height: 40vh;.
Another way, as in below sample, is to change the 100% in height: 100% to 100vh.
I guess this works better because viewport units like vh is a fixed unit, which percent is not.
Plnkr demo: https://plnkr.co/edit/66W4a2lOI58XLudCmkw9?p=preview
html {
height: 100vh;
}
body {
height: calc(100vh - 16px);
}
.main {
display: flex;
flex-direction: column;
height: 100vh;
width: 100%;
}
.max,
.all {
display: flex;
flex-direction: column;
width: 100%;
overflow-y: auto;
}
.max {
flex: 0 1 auto;
min-height: 103px;
max-height: 40%;
background-color: green;
}
.all {
flex: 1 1 auto;
min-height: 235px;
background-color: blue;
}
.content {
flex: 0 0 auto;
box-sizing: border-box;
height: 200px;
margin: 5px;
border: 1px dashed black;
background-color: white;
}
<div class="main">
<div class="max">
<div class="content"></div>
</div>
<div class="all">
<div class="content"></div>
</div>
</div>
Yes it feels buggy. If you increase the height of the window the height of the first box does not get updated unless:
you decrease the height again
"put your mouse over it" (did not quite get your meaning here)
IMHO this is a browser bug.
If you set flex-grow to anything greater 0 for the first box, the height gets updated correctly, if you increase the height of the window (as you would expect) But using flex-grow isn't an option as the box could potentially grow bigger than its content.
Rather than using max-height:40% you should use the exact same height as you use for .content and use flex-grow: 1 as well to circumvent the "browser bug"

flexbox parent smaller than child elements on browser resize [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 5 years ago.
Why is the parent smaller than the children on narrow screens?
See snippet... then resize your browser (width-wise) to be smaller than the pink box. The scroll bars should appear. Scroll back to the right on the page and note the green background is smaller than the pink area and there is a white spot on the right.
So few questions:
Why does it happen?
How do I prevent the parent div's green background from getting smaller than the pink box/div when the browser is resized without setting an explicit width on the parent (or anywhere else) or using overflow:hidden?
Is there a flexbox solution to this problem?
Thanks,
Thomas
.parent {
height: 400px;
background-color: green;
display: flex;
}
.item {
height: 100px;
background-color: pink;
padding: 10px;
}
<div class="parent">
<div class="item">looooooooooooooooooooooooooooong</div>
<div class="item">looooooooooooooooooooooooooooong</div>
</div>
Flex items, by default, cannot be smaller than the size of their content. Therefore, while the parent can shrink, the flex items cannot shrink past the length of the text. This causes the overflow and, as a result, the column of white space below.
The initial setting on flex items is min-width: auto. In order for each item to stay within the container, switch to min-width: 0.
.parent {
height: 400px;
background-color: green;
display: flex;
}
.item {
height: 100px;
background-color: pink;
padding: 10px;
min-width: 0; /* NEW */
}
<div class="parent">
<div class="item">looooooooooooooooooooooooooooong</div>
<div class="item">looooooooooooooooooooooooooooong</div>
</div>
Now the pink boxes are not overflowing the container anymore.
However, the text is now overflowing the pink boxes.
The question doesn't specify behavior for the text, but here's one possible solution:
.parent {
height: 400px;
background-color: green;
display: flex;
}
.item {
height: 100px;
background-color: pink;
padding: 10px;
min-width: 0; /* NEW */
text-overflow: ellipsis; /* NEW */
white-space: nowrap; /* NEW */
overflow: hidden; /* NEW */
}
<div class="parent">
<div class="item">looooooooooooooooooooooooooooong</div>
<div class="item">looooooooooooooooooooooooooooong</div>
</div>
It happens, because your .parent is a normal block element (flex is also a block-level container) and that is initialized with width:auto;, which is in your case the width of the viewport. So scrolling to the right will show white space because your div's width is smaller than the whole scrollable area.
You do that with setting the .parent to an inline element, which will respond to its childrens width.
Yes, just use display: inline-flex; on the .parent.
.parent {
height: 400px;
width: 100%;
background-color: green;
display: inline-flex;
}
.item {
flex: 1;
height: 100px;
background-color: pink;
padding: 10px;
}
<div class="parent">
<div class="item">looooooooooooooooooooooooooooong</div>
<div class="item">looooooooooooooooooooooooooooong</div>
</div>
See display on MDN.

Div width 100% minus fixed amount of pixels

How can I achieve the following structure without using tables or JavaScript? The white borders represent edges of divs and aren't relevant to the question.
The size of the area in the middle is going to vary, but it will have exact pixel values and the whole structure should scale according to those values. To simplify it, I'd need a way to set "100% - n px" width to the top-middle and bottom-middle divs.
I'd appreciate a clean cross-browser solution, but in case it's not possible, CSS hacks will do.
Here's a bonus. Another structure I've been struggling with and end up using tables or JavaScript. It's slightly different, but introduces new problems. I've been mainly using it in jQuery-based windowing system, but I'd like to keep the layout out of the script and only control the size of one element (the middle one).
New way I've just stumbled upon: css calc():
.calculated-width {
width: -webkit-calc(100% - 100px);
width: -moz-calc(100% - 100px);
width: calc(100% - 100px);
}​
Source: css width 100% minus 100px
You can use nested elements and padding to get a left and right edge on the toolbar. The default width of a div element is auto, which means that it uses the available width. You can then add padding to the element and it still keeps within the available width.
Here is an example that you can use for putting images as left and right rounded corners, and a center image that repeats between them.
The HTML:
<div class="Header">
<div>
<div>This is the dynamic center area</div>
</div>
</div>
The CSS:
.Header {
background: url(left.gif) no-repeat;
padding-left: 30px;
}
.Header div {
background: url(right.gif) top right no-repeat;
padding-right: 30px;
}
.Header div div {
background: url(center.gif) repeat-x;
padding: 0;
height: 30px;
}
While Guffa's answer works in many situations, in some cases you may not want the left and/or right pieces of padding to be the parent of the center div. In these cases, you can use a block formatting context on the center and float the padding divs left and right. Here's the code
The HTML:
<div class="container">
<div class="left"></div>
<div class="right"></div>
<div class="center"></div>
</div>
The CSS:
.container {
width: 100px;
height: 20px;
}
.left, .right {
width: 20px;
height: 100%;
float: left;
background: black;
}
.right {
float: right;
}
.center {
overflow: auto;
height: 100%;
background: blue;
}
I feel that this element hierarchy is more natural when compared to nested nested divs, and better represents what's on the page. Because of this, borders, padding, and margin can be applied normally to all elements (ie: this 'naturality' goes beyond style and has ramifications).
Note that this only works on divs and other elements that share its 'fill 100% of the width by default' property. Inputs, tables, and possibly others will require you to wrap them in a container div and add a little more css to restore this quality. If you're unlucky enough to be in that situation, contact me and I'll dig up the css.
jsfiddle here: jsfiddle.net/RgdeQ
Enjoy!
You can make use of Flexbox layout. You need to set flex: 1 on the element that needs to have dynamic width or height for flex-direction: row and column respectively.
Dynamic width:
HTML
<div class="container">
<div class="fixed-width">
1
</div>
<div class="flexible-width">
2
</div>
<div class="fixed-width">
3
</div>
</div>
CSS
.container {
display: flex;
}
.fixed-width {
width: 200px; /* Fixed width or flex-basis: 200px */
}
.flexible-width {
flex: 1; /* Stretch to occupy remaining width i.e. flex-grow: 1 and flex-shrink: 1*/
}
Output:
.container {
display: flex;
width: 100%;
color: #fff;
font-family: Roboto;
}
.fixed-width {
background: #9BCB3C;
width: 200px; /* Fixed width */
text-align: center;
}
.flexible-width {
background: #88BEF5;
flex: 1; /* Stretch to occupy remaining width */
text-align: center;
}
<div class="container">
<div class="fixed-width">
1
</div>
<div class="flexible-width">
2
</div>
<div class="fixed-width">
3
</div>
</div>
Dynamic height:
HTML
<div class="container">
<div class="fixed-height">
1
</div>
<div class="flexible-height">
2
</div>
<div class="fixed-height">
3
</div>
</div>
CSS
.container {
display: flex;
}
.fixed-height {
height: 200px; /* Fixed height or flex-basis: 200px */
}
.flexible-height {
flex: 1; /* Stretch to occupy remaining height i.e. flex-grow: 1 and flex-shrink: 1*/
}
Output:
.container {
display: flex;
flex-direction: column;
height: 100vh;
color: #fff;
font-family: Roboto;
}
.fixed-height {
background: #9BCB3C;
height: 50px; /* Fixed height or flex-basis: 100px */
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}
.flexible-height {
background: #88BEF5;
flex: 1; /* Stretch to occupy remaining width */
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}
<div class="container">
<div class="fixed-height">
1
</div>
<div class="flexible-height">
2
</div>
<div class="fixed-height">
3
</div>
</div>
The usual way to do it is as outlined by Guffa, nested elements. It's a bit sad having to add extra markup to get the hooks you need for this, but in practice a wrapper div here or there isn't going to hurt anyone.
If you must do it without extra elements (eg. when you don't have control of the page markup), you can use box-sizing, which has pretty decent but not complete or simple browser support. Likely more fun than having to rely on scripting though.
Maybe I'm being dumb, but isn't table the obvious solution here?
<div class="parent">
<div class="fixed">
<div class="stretchToFit">
</div>
.parent{ display: table; width 100%; }
.fixed { display: table-cell; width: 150px; }
.stretchToFit{ display: table-cell; vertical-align: top}
Another way that I've figured out in chrome is even simpler, but man is it a hack!
.fixed{
float: left
}
.stretchToFit{
display: table-cell;
width: 1%;
}
This alone should fill the rest of the line horizontally, as table-cells do. However, you get some strange issues with it going over 100% of its parent, setting the width to a percent value fixes it though.
We can achieve this using flex-box very easily.
If we have three elements like Header, MiddleContainer and Footer. And we want to give some fixed height to Header and Footer. then we can write like this:
For React/RN(defaults are 'display' as flex and 'flexDirection' as column), in web css we'll have to specify the body container or container containing these as display: 'flex', flex-direction: 'column' like below:
container-containing-these-elements: {
display: flex,
flex-direction: column
}
header: {
height: 40,
},
middle-container: {
flex: 1, // this will take the rest of the space available.
},
footer: {
height: 100,
}
what if your wrapping div was 100% and you used padding for a pixel amount, then if the padding # needs to be dynamic, you can easily use jQuery to modify your padding amount when your events fire.
I had a similar issue where I wanted a banner across the top of the screen that had one image on the left and a repeating image on the right to the edge of the screen. I ended up resolving it like so:
CSS:
.banner_left {
position: absolute;
top: 0px;
left: 0px;
width: 131px;
height: 150px;
background-image: url("left_image.jpg");
background-repeat: no-repeat;
}
.banner_right {
position: absolute;
top: 0px;
left: 131px;
right: 0px;
height: 150px;
background-image: url("right_repeating_image.jpg");
background-repeat: repeat-x;
background-position: top left;
}
The key was the right tag. I'm basically specifying that I want it to repeat from 131px in from the left to 0px from the right.
In some contexts, you can leverage margin settings to effectively specify "100% width minus N pixels". See the accepted answer to this question.