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.
Related
This question already has answers here:
Can't scroll to top of flex item that is overflowing container
(12 answers)
Closed 4 years ago.
I've been on this for a while now and tried a lot of the solutions I've seen across different Stackoverflow questions / blogposts / ... But I honestly can't figure out what's going wrong.
I've got a flexed div with two divs in there. The top div A has a fixed height, the other div B fills the rest using flex: 1;. If the screen is resized and it's smaller than the height of A + B together, then B will start overflowing. I want it to scroll, but I also want the content to be fully visible when scrolling. For some reason which I can't figure out, the content renders out of the top of div B as you can see in this screenshot of my fiddle:
Some of the previously asked questions got me somewhere. For example setting the body to height: auto;, but then when my screen is bigger than A + B it can't be center aligned anymore. min-height: 0; also doesn't seem to help in this case.
How can I make sure my container overflows but will fully show the content of it?
You can solve the issue by giving .second:
flex-basis: auto;
flex-shrink: 0;
Or, with shorthand: flex: 1 0 auto;
Working example:
html, body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
body {
display: flex;
flex-direction: column;
}
.second {
flex: 1 0 auto;
background: blue;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
min-height: 0;
overflow: auto;
}
.container {
display: flex;
flex-direction: column;
width: 100%;
max-width: 500px;
min-height: 0;
/* added this to make it obvious. Obviously, not needed */
padding: 2rem 0;
}
.container-child {
height: 110px;
background: green;
width: 100%;
}
.container-child:not(:last-child) {
margin-bottom: 30px;
}
<div class="second">
<div class="container">
<div class="container-child"></div>
<div class="container-child"></div>
<div class="container-child"></div>
</div>
</div>
I added some top and bottom padding to .container to make it obvious that it's working - but it's not needed.
Now let's look at why this is happening. When you apply .second { flex:1; } it means:
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;
... which allows it to have a smaller size than its contents.
Whenever you have a bigger child centered in a smaller parent, the browser won't provide a scrollbar to top (or to left, when horizontal), because then , if the top of the parent and the top of the child coincide and the child is bigger than the parent, the child is no longer centered, is it?
The same happens when using other centering techniques and you center a bigger child in a smaller parent.
To fix the problem, you need to prevent the child from outgrowing the parent.
In this case, it meant sizing .second based from its content (flex-basis: auto) and not allowing it to shrink: (flex-shrink: 0;).
To better visualize the issue, consider this example:
.left, .right {
position: relative;
border: 1px solid red;
padding: 1rem 5rem;
}
.left {
left: -5rem;
}
.right {
right: -5rem;
}
<div class="left">
I'm taken left
</div>
<div class="right">
I'm taken right
</div>
If the browser provided scrollbars to allow you to scroll to beginning of .left, it would mean that left: -5rem did not apply. I hope that makes sense, I can't explain it better.
I have a problem with Firefox on a really specific graphic implementation.
I think you may understand the problem just by testing this fiddle: on firefox you'll see the problem, on any other browser you'll see the expected result (including IE9).
Design I need:
PNG illustration
I have a main block (dashed border) with a fixed width.
There is 2 lines, one above the other, within the main block. The 2 lines must be align on the right of the main block
Each line contains 2 children. The left ones have a dynamic text (gray background), the right ones are optionnals (blue background). The above right one contains an icon (orange) with a fixed width, the bellow right one is a dynamic temperature (with one decimal maximum).
Blocks are separated by a fixed 5px margin.
Texts and icon must be vertically centered.
In any case, the 2 lines need to have the same width: the smaller one takes the width of the bigger one.
If one line (or both) becomes too large for the main block, the left text (gray background) automatically linebreak.
HTML Code:
<div class="main-wrapper">
<div class="container">
<div class="content upper">
<div class="right-block"><!-- This block is optionnal -->
<div class="icon"></div>
</div>
<div class="left-block">
<div class="vertically-centered">
<p>
Some dynamic text
</p>
</div>
</div>
</div>
<div class="content lower">
<div class="right-block"><!-- This block is optionnal -->
<div class="vertically-centered">
<span>
21,5°
</span>
</div>
</div>
<div class="left-block">
<div class="vertically-centered">
<p>
Some other dynamic text
</p>
</div>
</div>
</div>
</div>
</div>
CSS Code:
/* utilities */
.vertically-centered {
display: table;
height: 100%;
width: 100%;
}
.vertically-centered > * {
display: table-cell;
vertical-align: middle;
}
/* custom styles */
.container {
display: inline-block;
float: right;
max-width: 100%;
}
.content {
width: 100%;
margin: 5px 0px;
height: 85px;
}
.right-block, .left-block {
height: 100%;
}
.right-block {
float: right;
font-size: 42px;
margin-left: 5px;
background-color: lightblue;
}
.left-block {
font-size: 25px;
line-height: 25px;
overflow: hidden;
padding: 0 20px;
text-align: left;
background-color: lightgray;
}
.upper .right-block {
width: 85px;
}
.lower .right-block {
padding: 0 15px;
}
.icon {
position: relative;
top: 20%;
left: 20%;
width: 60%;
height: 60%;
background-color: orange;
}
What I already tried:
Put a display: inline-block on the .left-block div, as suggested here, but it doesn't satisfy the need to have the same width on both lines.
Put a display: inline-block on the .content div; makes the line 100% width on other browsers, and create a big right gap within the .left-block on firefox.
Use white-space: nowrap on the .left-block; didn't help.
Make the .left-block div floating (right or left), but it doesn't work if the text is too large for the main container
And a lot of other things but not a single one compatible with all the browsers (Chrome, Firefox, Safari, IE9+, Edge)...
A precision although I don't think it will change anything: it is responsive.
I'm trying something with flexbox but... IE9... If anybody has a suggestion.
You can use the CSS word-break property to allow line breaks in the middle of long words:
.content {
width: 100%;
margin: 5px 0px;
height: 85px;
word-break: break-all;
}
I found out a solution with flexbox!
I added a display: flex to the .content div with flex-direction: row-reserve to keep the order of the element and still be able to use float: right for IE9.
In addition, there is a flex: auto property on .left-block divs to take as much space as possible (Note: IE11 needs flex-basis to be set to be able to calculate the space wanted by the flex-grow property. That's why I used auto instead of 0 on the flex property. See details)
The completed CSS code
.content {
width: 100%;
margin: 5px 0px;
height: 85px;
display: flex; /* Initialize flexbox */
flex-direction: row-reverse; /* keep the order of the element */
border: 1px dashed gray;
}
.left-block {
font-size: 25px;
line-height: 25px;
overflow: hidden;
padding: 0 20px;
text-align: left;
background-color: lightgray;
flex: auto; /* the text blocks take all the available space */
}
Here's the fiddle with the correction. Sometimes IE9 takes 2 lines of text instead of 1 (the text is 2px larger that the container, I don't know why...) but atleast it's readable!
As described by the image there are two elements: A parent (dark gray) and child (not so dark gray). The width and height of the parent is fluid. The ratio of the child i 1:1 or y:y where y is equal to the height of the parent.
I've tried to find ways to solve this using flex, calc, padding etc but have reached the end of the road. Any ideas how to solve this with pure CSS are much appreciated.
EDIT: I realize now I should have added more details regarding the usage of this scenario. As well as what I consider to be a dynamic height. Dynamic height for me suggests that the height is decided by the amount of content it contains. So I added some HTML to clarify. The .content div may be unnecessary if you can put the content directly in the .container div. But that depends on how you write the CSS:
<div class="container">
<div class="content">
Here is some text. It can be long and it can be short.
It will affect the height of the .container thus also
the height and width of the .square.
</div>
<div class="square">1:1</div>
</div>
I think it is not possible to do what you try!You can't get parents height without JS. But maybe there is another solution. Does your parent container also has a fixed proportion?
This question was quite old. But today I found a quite-tricky solution that may help. That is, I utilize the property of image (svg here) that preserve the aspect ratio while scaling. So I insert an empty svg and make its height fit the parent. Then we have its width equals to its height. (You can change the 1 1 in the part <svg viewBox="0 0 1 1" > to change the ratio).
See the example below. Sorry for my bad English.
.outer {
display: flex;
/* This is just for the example */
width: 700px; /* x */
height: 100px; /* y */
font-size: 18px;
font-family: Verdana, Geneva, sans-serif;
}
.left {
flex-grow: 1
/* This is just for the example */
color: #cddfc9;
background-color: #636363;
padding: 10px;
height: 100%;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
}
.child {
height: 100%;
position: relative;
display: inline-flex;
}
/* This is the trick */
.child svg {
height: 100%;
width: 100%;
}
.child > .content {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
/* This is just for the example */
color: white;
background-color: #8a8a8a;
display: flex;
align-items: center;
justify-content: center;
}
<div class="outer">
<div class="left">
Text of various length be here...
</div>
<div class="child">
<svg viewBox="0 0 1 1" ></svg>
<div class="content">
yxy
</div>
</div>
</div>
you can use the vh property for this. Set the height of your parent div in vh and then use the same vh value for the width of your child div and set the height of the child div to 100%.
#parent{
position: absolute;
left: 0;
top:0;
width: 400px;
height: 50vh;
background-color: red;
}
#child{
position: relative;
float: right;
height: 100%;
width: 50vh;
background-color: blue;
}
<div id="parent">
<div id="child"></div>
</div>
I am trying to set the width of a div element to the width of it's longest child element, which in this case happens to be a div that I want locked to the bottom of the parent div. I am also not using a fixed height for the parent, because I do not know how big the children will need to be
Here is my html/css:
HTML:
<div id ="header-right">
<div id="content1"></div>
<div id="footer"></div>
</div>
CSS:
#header-right{
background-color: red;
position: relative;
display: inline-block;
height: 300px; /*The actual width is unknown, this is just for example*/
}
#content1{
background-color: blue;
width: 200px;
height: 100px;
}
#footer{
background-color: cyan;
position: absolute;
bottom: 0;
width: 300px; /*Also an unknown value*/
height: 25px;
}
You can have a look at this jfiddle to see what happens:
https://jsfiddle.net/rkdqp9m5/2/
You can see the container div ignores the footer, since it is absolutely positioned.
However, if I do not use absolute positioning for the footer, then I cannot lock the footer to the bottom of the div, as you can see in this jfiddle
https://jsfiddle.net/rkdqp9m5/3/
I want to lock the footer to the bottom of the container, but I also want the parent's width to be based off the footer. I do not want to use tables for this, and I do not wan to used fixed widths or heights, as the container's and the footer's dimensions will be based off of images whose widths I do not know.
Edit: I would also like to keep this strictly in HTML/CSS, if possible
If you're OK with browser requirements of flexbox, you could do:
#header-right {
background-color: red;
padding: 20px 0px 0px 0px;
height: 300px;
display: inline-flex;
flex-direction: column;
justify-content: space-between;
}
#content1 {
background-color: blue;
width: 200px;
height: 100px;
align-self: flex-start;
}
#footer {
background-color: cyan;
width: 300px;
height: 25px;
align-self: flex-end;
}
<div id="header-right">
<div id="content1"></div>
<div id="footer"></div>
</div>
JSFIDDLE DEMO with all the necessary vendor prefixes.
Does this help: Relative parent DIV to inherit the width of absolute child DIV
What it suggests is that you can't use pure CSS, but you can use Javascript to achieve what you're trying to do.
I want to obtain this layout:
<------------ Browser Width 100% ------------>
[left][----- center: fixed width -----][right]
The center column has a fixed pixel width
The left and right columns fill in the remaining viewport width equally
The example below breaks when the viewport width is not wide enough, and getting the correct percentage width is hard because of the fixed width center column.
div {
display: inline-block;
background: #F90;
height: 100px;
width: 20%;
}
.center {
width: 500px;
background: #FF0;
}
<div class="left">left (fill available space)</div>
<div class="center">fixed width</div>
<div class="right">right (fill available space)</div>
Three ways to achieve a fluid / fixed column layout
Method #1 - with display: table
This is one of the easiest methods and has good browser support.
Compatibility: IE8 + and all modern browsers
body gets display: table - this could also be applied to a div wrapper instead.
table-layout: fixed ensures the middle column remains fixed width
the direct div children of body get display: table-cell
the body gets a min-width to ensure the left and right columns do not get too small
the middle column is fixed at your desired width (500px in this example)
the left and right columns inherit the remaining page width
#1 - Working Example
html {
height: 100%;
}
body {
display: table;
height: 100%;
margin: 0;
width: 100%;
table-layout: fixed;
min-width: 800px;
}
body > div {
display: table-cell;
}
.left {
background: #000;
}
.middle {
background: #F00;
width: 500px;
}
.right {
background: #F90
}
<div class="left">
</div>
<div class="middle">
</div>
<div class="right">
</div>
Method #2 - with display: inline-block and width: calc(x - y)
Compatibility: Calc is compatible in IE 9 + and most modern browsers. There are javascript fallbacks available as well.
The direct div children of body are given display: inline-block and vertical-align: top. They will align themselves to the top of the browser window on the same line
The middle column gets its fixed width
The left and right columns are given calc(50% - 250px); this calculates 50% of the page width minus half of the width of the fixed middle column.
box-sizing: border-box incorporates padding and borders into the width and height
#2 - Working Example
Note how the closing and opening divs tags have no gaps between them; this is to prevent an inline gap between elements.
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
}
body {
min-width: 800px;
}
body > div {
display: inline-block;
width: calc(50% - 250px);
height: 100%;
vertical-align: top;
}
.left {
background: #000;
}
.middle {
background: #F00;
width: 500px;
}
.right {
background: #F90
}
<div class="left"></div><div class="middle"></div><div class="right"></div>
Method #3 - with display: flex
This is a really awesome method, but is not supported with older browsers :(
Compatibility: IE11 and most modern browsers
The body gets display: flex and height: 100vh (100% of the viewport height)
The direct children get flex: 1 and will grow and shrink
The middle column gets its fixed width and flex: 0 0 auto; it will not grow or shrink
Here is a useful guide to Flexbox.
#3 - Working Example
body {
display: flex;
height: 100vh;
margin: 0;
min-width: 800px;
}
body > div {
flex: 1;
}
.left {
background: #000;
}
.middle {
background: #F00;
width: 500px;
flex: 0 0 auto;
}
.right {
background: #F90
}
<div class="left">
</div>
<div class="middle">
</div>
<div class="right">
</div>