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>
Related
I'm trying to center an element in the middle of the page. I can center it just fine, but if I resize the page vertically until the view height is smaller than the centered element, the element goes offscreen vertically without a scrollbar. You can see a demonstration of the issue here:
http://codepen.io/mse/pen/BWayXV
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
.outer {
text-align: center;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.inner {
display: inline-block;
width: 400px;
height: 800px;
background: grey;
}
<div class="outer">
<div class="inner"></div>
</div>
I should mention that I have tried a couple of other methods of vertical centering, including flexbox, and I'm still running into the same issue. Is there a way to solve this problem with this method of vertical centering, or is there at least a vertical centering method that does not have this issue?
Try this
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
.outer {
display:flex;
justify-content:center;
align-items:center;
}
.inner {
background: #ccc;
width: 400px;
height: 600px
}
<div class="outer">
<div class="inner"> I'm a block-level element centered vertically within my parent.</div>
</div>
More info: https://css-tricks.com/centering-css-complete-guide/
CSS VH center generator: http://howtocenterincss.com/
This should work
* {
padding: 0;
margin: 0;
}
html, body {
height: 100vh;
}
.outer {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.inner {
width: 400px;
height: 800px;
background: grey;
}
<div class="outer">
<div class="inner"></div>
</div>
You can try to limit the size of your inner element. If you define size by a fixed px amount it will start scrolling as soon as the screen becomes smaller than that px amount. If you are ok with changing the height of the inner element you could use vh or you can implement #media queries to decrease the size on smaller screens. Here#s an example:
.inner { height: 100vh; /* 100 view height percentage*/}
Note: The viewport-percentage lengths are relative to the size of the initial containing block and affected by the presence of scrollbars on the viewport.
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 would like to achieve a layout that looks like this:
I am interested in a css/html only solution, so no javascript required.
The widths of both divs are dynamic, so I cannot use any static margins.
The spacing between the sides of the divs, and the top, should be the same.
I tried using margin: auto auto 0 auto on the inner div, as you can see in this jsfiddle, but it only works for left and right.
Note, the following attempt doesn't answer the question fully, since the width of the child cannot be dynamic.
The idea is to use a percentage width + percentage margin-top values on the child. It's a responsive layout, see the comments in the code, and try it out on different window sizes.
JSFiddle: http://jsfiddle.net/jkoycs6e/
body {
margin: 0;
}
.outer {
height: 100vh; /*for demo only*/
background: teal;
overflow: auto;
}
.inner {
width: 80%;
background: gold;
margin: auto;
margin-top: 10%; /* 100%-80%/2 */
}
<div class="outer">
<div class="inner">
hello<br/>hello<br/>hello
</div>
</div>
This is not possible. At least not without using javascript. There is no css-only solution.
If you put align="center" in your div you'll get to the middle of the screen every time but it's not going to be supported in HTML5 so I recommend the 50:50 approach.
div
{
text-align:center;
margin-top:50%;
margin-bottom:50%;
}
Hope that helps. ^^
Set the outer parent's overflow to auto and give your margin-top a relative value. Something like this:
.outer {
background: blue;
overflow: auto;
}
.inner {
background:yellow;
width: 100px;
height: 100px;
margin: 1em auto 0 auto;
}
<div class="outer">
<div class="inner">
</div>
</div>
This seems to work:
.outer {
height: 500px;
width: 300px;
background: blue;
position: relative;
}
.inner {
width: 80%;
height: 200px;
background:green;
position: absolute;
margin-left: 10%;
margin-right: 10%;
margin-top: 10%;
margin-bottom: 0;
}
You can change the percentages marked for the margins as per your intended value for k.
Here's the fiddle
EDIT: Note that the width of inner has to be set in terms of percentages for this to work. Also note that when a margin is specified in terms of percentage, the margin's value is computed as a percentage of the width of the container. Even for the vertical margins, the percentage is applied on the width (and NOT the height) of the container.
Here's an SO post that's helpful in understanding how to position elements with respect to their container.
This answer doesn't actually make use of the margin property, nor does it have only two div.
body {
font-size: 26px;
text-align: center;
font-family: monospace;
}
#container {
display: inline-block;
position: relative;
width: 100%;
}
#dummy {
margin-top: 20%;
}
#element {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: silver
/* show me! */
}
#wrapper {
display: table;
width: 100%;
}
#row {
display: table-header-group;
}
#left {
display: table-cell;
background-color: chartreuse;
width: 20%;
}
#incenter {
display: table-cell;
background-color: aqua;
}
#right {
display: table-cell;
background-color: chartreuse;
width: 20%;
}
<div>
<div id="container">
<div id="dummy"></div>
<div id="element">
k (20%)
</div>
</div>
<div id="wrapper">
<div id="row">
<div id="left">width = k (20%)</div>
<div id="incenter">incenter</div>
<div id="right">width = k (20%)</div>
</div>
</div>
</div>
Another example with measurements in pixels is here.
For explanation refer:
https://stackoverflow.com/a/12121309/2534513
https://stackoverflow.com/a/6615994/2534513
I have actually combined techniques mentioned in above two answers to make this one.
Using JavaScript would have been a lot easier.
Why in the following example the height of the inner div is not like wrapper's div ?
Live demo here.
HTML:
<div class="wrapper">
<div class="inner">Hello</div>
<div class="inner">Peace</div>
</div>
CSS:
.wrapper {
background-color: #000;
min-height: 100px;
}
.inner {
display: inline-block;
background-color: #777;
height: 100%;
}
If I change min-height: 100px; to height: 100px;, then it looks OK. But, in my case, I need min-height.
Some properties in CSS inherit the value of the parent automatically, some don't. Minimum height must be explicitly stated when you want it to inherit the parent's value:
min-height: inherit;
I believe this is the output you want: http://jsfiddle.net/xhp7x/
.wrapper {
display: table;
background-color: #000;
height: 100px;
width: 100%;
}
.wrapper2 {
height: 100%;
display: table-row
}
.inner {
height: 100%;
display: inline-block;
background-color: #777;
margin-right: 10px;
vertical-align: top;
}
Had to add a second DIV wrapper2.
Tested on chrome and firefox.
You want to specify both, CSS height is not the same as min-height. You want to specify both height and min-height.
height = When used as a %, this is a percent of the window height
min-height = as you drag the window smaller, the DIV with a % height will continue to reduce until it hits the min-height
max-height = as you drag the window larger, the DIV with a % height will continue to increase until it hits the max-height
http://jsfiddle.net/gpeKW/2/ I've added a sample here with borders.
Slight change to the answer from your comment, you are pretty much correct from your original CSS.
The below HTML will have a minimum div height of 100px. As the size of the inner DIV increases, the wrapper will automatically expand. I have demonstrated this by adding a style attribute to the first inner class.
<html>
<head>
<title>Untitled Page</title>
<style type="text/css">
.wrapper
{
background-color: #000;
min-height:100px;
}
.inner
{
display: inline-block;
background-color: #777;
height: 100%;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="inner" style="height:200px">test</div>
<div class="inner">Peace</div>
</div>
</body>
</html>
I know one way to set the div child height the same as its parent div height is to use relative for the parent and absolute position for the child.
.wrapper {
background-color: #000;
min-height: 100px;
position: relative;
}
.inner {
display: inline-block;
background-color: #777;
position: absolute;
height: 100%;
}
But this way will cause some problem, you have to adjust the child element so that it will be displayed properly
P/s: Why don't you set it to the same height as its parent height? I mean, 100% is not x%... just thinking..
Anyway, happy coding ;)
I certainly joined answers and the result using 'min-height' for the -main HTML tag- (class = "main-page-container"):
HTML:
<div id="divMainContent">
<!-- before or after you can use multiples divs or containers HTML elements-->
<div> </div>
<div> </div>
<main class="main-page-container">
<div class="wrapper">
1
<div class="wrapper2">
2
<div class="child">3</div>
</div>
</div>
</main>
<!-- before or after you can use multiples divs or containers HTML elements-->
<div class="footer-page-container bg-danger" > more relevant info</div>
</div>
CSS:
/*#region ---- app component containers ---- */
#divMainContent {
height: 100%;
display: flex;
flex-direction: column;
/*optional: max width for screens with high resolution*/
max-width: 1280px;
margin:0 auto;
}
.main-page-container {
display: inline-table;
height: 70%;
min-height: 70%;
width: 100%;
}
.footer-page-container{
flex:1; /* important in order to cover the rest of height */
/* this is just for your internal html tags
display: flex;
flex-direction: column;
justify-content: space-between; */
}
/*#endregion ---- app component containers ---- */
.wrapper {
background: blue;
max-width: 1280px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100%;
}
.wrapper2 {
width: 90%;
margin: auto;
background: pink;
display: flex;
flex-wrap: wrap;
gap: 20px;
height: 90%;
}
.child {
min-height: 100px;
min-width: 300px;
background: orange;
position: relative;
width: 33%;
}
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.