I have an outerWrapper, innerWrapper, and children. outerWrapper has a height of 300px, and is display: flex. innerWrapper is also display: flex, and is flex-direction: column. innerWrapper doesn't have a height set to it.
When I add align-items: with a value of anything but strecth to outerWrapper, the children display one long column. They ignore the 300px height. Here's an image describing it:
When it should be like this:
If I set a height, I will get the second image. i.e. the way I want it to look. I can't set a fixed height, it needs to be dynamic.
I tried the following:
innerWrapper.style.height = (lastChild.offsetTop - innerWrapper.offsetTop + lastChild.offsetHeight) + 'px';
but it didn't fix it. It just made the height to: 5 * 102 (5 = number of boxes; 102 = height + border).
How can I set a dynamic height to innerWrapper? (I can't do height: 100% because I won't be able to set align-items: flex-end or center.)
JSFiddle
var innerWrapper = document.getElementById('innerWrapper');
var lastChild = innerWrapper.lastElementChild;
newHight = lastChild.offsetTop - innerWrapper.offsetTop + lastChild.offsetHeight;
innerWrapper.style.height = newHight + 'px';
#outerWrapper {
height: 300px;
background-color: lightgreen;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: flex-end;
}
ul {
padding: 0;
margin: 0;
display: flex;
align-items: center;
flex-wrap: wrap;
flex-direction: column;
/*height: 206px;*/
}
li {
list-style-type: none;
width: 100px;
height: 100px;
background-color: lightblue;
border: 1px solid;
}
<div id="outerWrapper">
<ul id="innerWrapper">
<li class="child">I'm #01</li>
<li class="child">I'm #02</li>
<li class="child">I'm #03</li>
<li class="child">I'm #04</li>
<li class="child">I'm #05</li>
</ul>
</div>
Update
I don't think this is a duplicate of this question. It's more of a follow-up question.
Related
I'm trying to have a div centered in the screen. This div should have a specific width and height when it fits in the available window space, but it should shrink to fit when the available window space is not enough, but also, maintaining its original aspect ratio.
I've been looking at lots of examples that work for a decreasing width, but none that work for both width and height changes in the window size.
Here's my current CSS:
* {
border: 0;
padding: 0;
margin: 0;
}
.stage_wrapper {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
width: 960px;
height: 540px;
max-width: 90%;
max-height: 90%;
display: flex;
justify-content: center;
align-items: center;
background: chocolate;
object-fit: contain; /* I know this is for images, it's an example of what I'm looking for */
}
And, my current HTML:
<div class="stage_wrapper">
<div class="stage">
<p>Some text</p>
</div>
</div>
This is showing a centered div that has a fixed width of 960px and a fixed height of 540px. It should never be bigger than that.
Then, if I change the size of my window to have a smaller width or height than that, the div element is successfuly shrinking - except it is not maintaining the original aspect ratio, and that is what I'm looking for. I want it to respond to changes in both width and height.
Is this possible at all?
The aspect-ratio ref property has a good support now so you can use the below:
body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
--r: 960 / 540;
aspect-ratio: var(--r);
width:min(90%, min(960px, 90vh*(var(--r))));
display: flex;
justify-content: center;
align-items: center;
background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>
Old answer
Here is an idea using viewport unit and clamp(). It's a kind of if else to test if the width of the screen is bigger or smaller than the height (considering the ratio) and based on the result we do the calculation.
In the code below with have two variables cv and ch and only one of them will be equal to 1
If it's cv then the width is bigger so we set the height to cv and the width will be based on that height so logically cv/ratio
If it's ch then the height is bigger so we set the width to cv and the height will be based on that width so logically ch/ratio
In the clamp() I am using 1vh/1vw that I multiple by 90 which is equivalent to your 90% to have 90vh/90vw
body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
--r: calc(960 / 540);
--cv: clamp(0px,(100vw - 100vh*var(--r))*10000,1vh);
--ch: clamp(0px,(100vh*var(--r) - 100vw)*10000,1vw);
height: calc((var(--cv) + var(--ch)/var(--r)) * 90 );
width: calc((var(--ch) + var(--cv)*var(--r)) * 90 );
max-width: 960px;
max-height: 540px; /* OR calc(960px/var(--r)) */
display: flex;
justify-content: center;
align-items: center;
background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>
In theory the clamp can be simplified to:
--cv: clamp(0px,(1vw - 1vh*var(--r)),1vh);
--ch: clamp(0px,(1vh*var(--r) - 1vw),1vw);
But to avoid any rounding issue and to not fall into values like 0.x I consider a big value to make sure it will always be clamped to 1 if positive
UPDATE
It seems there is a bug with Firefox so here is another version of the same code:
body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
--r: calc(960 / 540);
--cv: clamp(0px,(100vw - 100vh*var(--r))*100,90vh);
--ch: clamp(0px,(100vh*var(--r) - 100vw)*100,90vw);
height: calc((var(--cv) + var(--ch)/var(--r)) );
width: calc((var(--ch) + var(--cv)*var(--r)) );
max-width: 960px;
max-height: 540px; /* OR calc(960px/var(--r)) */
display: flex;
justify-content: center;
align-items: center;
background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>
Any solution using vw & vh assumes your container is the viewport. But what if you need an element that letterboxes to fit any container?
In other words, you want the behavior of object-fit: contain for an element that's not an <img> or <video>.
You need a container that centers both vertically and horizontally:
#container {
display: flex;
align-items: center;
justify-content: center;
}
and a contained object with fixed aspect-ratio that stretches either its width or height to 100%:
#object {
aspect-ratio: 16/9;
overflow: hidden;
[dimension]: 100%;
}
where [dimension] is width if the container is tall, and height otherwise.
If you don't know ahead of time whether it's going to be tall or not, a little javascript is needed to check for tallness and decide which dimension to stretch.
function update() {
const isTall = container.clientWidth / container.clientHeight < aspectRatio;
object.style.width = isTall ? '100%' : 'auto';
object.style.height = isTall ? 'auto' : '100%';
}
new ResizeObserver(update).observe(container);
I don't think this dimension switching can be accomplished in pure CSS without javascript.
Here's a demo.
You can set your height and width like:
height: 80vw;
width: 80vw;
Then, you can set the max height and width like:
max-height: 100vh;
max-width: 100vh;
Or if you have other things like headers in the way then:
max-height: calc(100vh - 32px);
max-width: calc(100vh - 32px);
The 32px is how many pixels(or other measurements) it takes up
Use this CSS maybe:
.stage_wrapper {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
width: 50vw;
height: 40vw;
max-width: 90%;
max-height: 90%;
display: flex;
justify-content: center;
align-items: center;
background: chocolate;
object-fit: contain; /* I know this is for images, it's an example of what I'm looking for */
}
You can adjust the code if you want to to be bigger or smaller, but this will let your div have a fixed aspect ratio.
I am trying to build simple gallery.
What I would like to achieve is this:
However, what I am actually achieving is this:
There is basically too much space between images and I can't find a way how to solve it. I understand that is because of justify-content: space-between; but perhaps there's another option that will put less space between the images?
Html
<div class="photoContainer>
<div class="ant-image">
...
</div>
</div>
Css
.photosContainer {
width: 80%;
height: 100%;
overflow: auto;
overflow-x: hidden;
display: flex;
align-content: space-between;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: 10px;
}
.ant-image {
height: fit-content;
flex-shrink: 0;
position: relative;
display: inline-block;
width: 200px;
}
With the space-between rule you cannot have the control of the space between the images.
My suggestion is to:
make the image gallery container smaller because you have a small number of photos
to have more control over the images you can use also for the single image a % width as you have done for the container.
hint: use property object-fit for the single images
you can use grid display instead of flex and solve your problem:
.photosContainer{
display:grid;
grid-template-columns:repeat(4 , 1fr);
}
I use the Divi theme on my Wordpress site and I am using their theme builder to design all of my category pages. I found this template which I like the look of - https://divisoup.com/css-grid-blog-layout/
This includes adding the below JavaScript code to do some of the design as well as the following CSS too.
<script>
//CSS Grid Blog Layout by Divi Soup
(function ($) {
$(document).ready(function () {
//Wrap first grid elements in containers
$(".ds-grid-blog-1 .et_pb_post").each(function () {
$(this).find(".entry-featured-image-url").wrapAll('<div class="ds-grid-blog-image"></div>');
$(this).find(".entry-title, .post-meta, .post-content").wrapAll('<div class="ds-grid-blog-content"></div>');
});
});
})(jQuery);
(function ($) {
$(document).ready(function () {
$(document).bind('ready ajaxComplete', function () {
//Wrap second grid elements in containers
$(".ds-grid-blog-2 .et_pb_post").each(function () {
$(this).find(".entry-featured-image-url").wrapAll('<div class="ds-grid-blog-image"></div>');
$(this).find(".entry-title, .post-meta, .post-content").wrapAll('<div class="ds-grid-blog-content"></div>');
});
//Move elements around
$(".et_pb_post").each(function () {
$(".post-meta", this).insertBefore($(".entry-title", this));
});
//Add button class to read more link
$(".et_pb_post a.more-link").addClass("et_pb_button");
//Replace pipes and remove commas from the meta
$(".et_pb_post").html(function () {
return $(this).html().replace(/\|/g, '/').replace(/,/g, '');
});
});
});
})(jQuery);
//End CSS Grid Blog Layout by Divi Soup
</script>
/*-----------------------------------------------*/
/*-------CSS Grid Blog Layout by Divi Soup-------*/
/*-----------------------------------------------*/
/*Blog layout settings, adjust these values only*/
:root {
--ds-white: #ffffff; /*The background colour for the post content and text colour for the second and third post content*/
--ds-grid-2-item: 250px; /*Minimum column width for second grid, decrease this value for more columns*/
--ds-grid-gap: 30px; /*The gap between posts*/
--ds-title-background: rgba(0, 0, 0, .5); /*The background colour of the titles on the second and third posts*/
}
/******************************************************/
/*You should not need to edit anything below this line*/
/******************************************************/
/*Set posts to flex and remove post margin*/
.ds-grid-blog .et_pb_post {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
margin-bottom: 0;
}
/*Set flex direction for second grid*/
.ds-grid-blog-2 .et_pb_post {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
/*Set post content to flex*/
.ds-grid-blog-content {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
background: var(--ds-white);
}
/*Remove image margin and resize for responsiveness*/
.ds-grid-blog .entry-featured-image-url {
margin-bottom: 0;
height: 100%;
width: auto;
}
.ds-grid-blog .et_pb_post a img {
height: 100%;
-o-object-fit: cover;
object-fit: cover;
}
/*Reset the read more link display*/
.ds-grid-blog a.more-link {
display: initial;
}
/*Add margin to excerpt*/
.ds-grid-blog .post-content p {
margin-bottom: 20px;
}
/*Pagination placement*/
.ds-grid-blog .pagination {
grid-column: 1/-1;
}
/*Set the grid for the first 3 posts*/
.ds-grid-blog-1 .et_pb_ajax_pagination_container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: var(--ds-grid-gap);
}
/*Set the grid for the remaining posts*/
.ds-grid-blog-2 .et_pb_ajax_pagination_container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--ds-grid-2-item), 1fr));
grid-gap: var(--ds-grid-gap);
}
/*First grid first post placement*/
.ds-grid-blog-1 .et_pb_post:first-child {
grid-column: 1 / -1;
}
/*First grid second post placement*/
.ds-grid-blog-1 .et_pb_post:nth-child(2) {
grid-column: 1 / 2;
}
/*First grid third post placement*/
.ds-grid-blog-1 .et_pb_post:nth-child(3) {
grid-column: 2 / 3;
}
/*First post content*/
.ds-grid-blog-1 .et_pb_post:first-child .ds-grid-blog-content {
width: 60%;
padding: 30px;
display: -webkit-box;
display: -ms-flexbox;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
}
/*Position and colour for second & third posts*/
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .ds-grid-blog-content {
background: var(--ds-title-background);
position: absolute;
left: 0;
right: 0;
bottom: 0;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
padding: 10px;
text-align: center;
}
/*Text colour for second & third posts*/
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .entry-title,
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .post-meta,
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .post-meta a {
color: var(--ds-white) !important;
}
/*Font size for second & third posts*/
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .entry-title {
font-size: 150% !important;
}
/*Hide excerpt for second & third posts and second grid posts*/
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .post-content,
.ds-grid-blog-2 .et_pb_post .post-content p {
display: none;
}
/*Remaining posts display*/
.ds-grid-blog-2 .et_pb_post .ds-grid-blog-content {
padding: 30px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
height: 100%;
}
/*Set margin for remaining posts*/
.ds-grid-blog-2 .et_pb_post .entry-title {
margin-bottom: 30px;
}
/*Keep read more link at bottom*/
.ds-grid-blog-2 .et_pb_post .post-content {
margin-top: auto;
}
/*Adjust for mobile*/
#media all and (max-width:980px) {
.ds-grid-blog-1 .et_pb_post:first-child {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.ds-grid-blog-1 .et_pb_post:first-child .ds-grid-blog-content {
width: 100%;
}
.ds-grid-blog-1 .et_pb_post {
grid-column: 1 / -1 !important;
}
}
/*-----------------------------------------------*/
/*-----End CSS Grid Blog Layout by Divi Soup-----*/
/*-----------------------------------------------*/
.more-link.et_pb_button {
text-transform: capitalize;
color: #3984BC;
}
This is the page in question - https://travellingpair.co.uk/destinations/europe/
I'm unsure as to what is causing the errors or what they mean, but it is stopping other things from loading on the page, such as the background image behind the page header, but the actual blog design is as expected.
The errors are:
UPDATE: Figured out that the issue was being caused by this piece of code:
$(".et_pb_post").html(function () {
return $(this).html().replace(/\|/g, '/').replace(/,/g, '');
});
It was removing the commas from within the srcset attribute as well and therefore making it invalid. It should have only been removing the commas and replacing the | with / in the post meta, but looks like it was doing it with the images as well. If anyone has any ideas on that bit it would be appreciated.
Okay so I did some digging and this was being caused by the following piece of code in the JS code:
$(".et_pb_post").html(function () {
return $(this).html().replace(/\|/g, '/').replace(/,/g, '');
});
This was meant to replace all pipes with slashes as well as removing the commas from the post-meta, but looks like the person who created the layout and code had set this to apply within the ".et_pb_post" class rather than ".post-meta" to just have it remove from the meta. Instead it was doing this in the whole post and that included taking the commas out of the "srcset" attribute meaning it was invalid.
I want all 100% height elements to expand when the size of the body expands.
In the example pressing the button will add a red div - the two columns adjacent should stretch to account for this. In the end all columns should reach the bottom completely, one with blue then red, the other two just blue.
I'm looking into flex, and it doesn't seem like this would work, but any suggestions are appreciated.
In any case best solution is CSS, but if this is impossible pure JS is also fine.
span = document.getElementsByTagName("span")[0];
function addelem() {
span.appendChild(document.createElement('div'));
};
html, body{
height: 100%;
}
span {
display: inline-block;
background-color: blue;
width: 30px;
height: 100%;
vertical-align: top;
}
div {
background-color: red;
width: 30px;
height: 30px;
}
<span><span></span></span>
<span></span>
<span><button onclick="return addelem()">+</button></span>
This is what I expect the frame to look like at the bottom after button is pressed and scrolled down:
EDIT
I changed the snippet so the button appends the div to an existing child and causes overflow, as per the comments below suggest.
An initial setting of a flex container is align-items: stretch. This means that flex items will expand to cover the full length of the container along the cross axis.
In a container with flex-direction: row, the cross axis is vertical, so items will expand to full height.
In your demo code, the divs (red) are being added as children of a span column (blue). These divs are being added to the end, forcing the column to grow.
In a row-direction flex container, with no heights specified that would override align-items: stretch, the other columns will follow suit.
span = document.getElementsByTagName("span")[0];
function addelem() {
span.appendChild(document.createElement('div'));
};
body {
display: flex;
min-height: 100vh;
}
body > span {
width: 30px;
margin-right: 5px;
background-color: blue;
display: flex;
flex-direction: column;
}
body > span:first-child span {
flex: 0 0 100vh;
}
div {
background-color: red;
width: 30px;
height: 30px;
}
button {
margin-bottom: auto;
}
<span><span></span></span>
<span></span>
<span><button onclick="return addelem()">+</button></span>
You should use Flexbox twice, once in the outer container, and once in the container containing the appended child elements.
Here is your modified code:
span = document.getElementsByTagName("span")[0];
function addelem() {
span.appendChild(document.createElement('div'));
};
html, body{
height: 100%;
/* new */
display: flex;
}
/* new */
body > span{margin-right: 4px;}
span {
/*display: inline-block;*/
background-color: blue;
width: 30px;
height: 100%;
vertical-align: top;
/* new */
display: flex;
flex-flow: column;
align-items: flex-end;
}
div {
background-color: red;
width: 30px;
height: 30px;
/* new */
flex: 1 0 auto;
}
<span><span></span></span>
<span></span>
<span><button onclick="return addelem()">+</button></span>
I have a flex box which has flex items in it, each having a certain order.
I want to set it so that when the flex box (not the screen, etc.) gets smaller than 500px the order changes (and maybe also one of the margins).
Here's the code:
HTML
<div class="flex-box">
<div class="flex-item-0"></div>
<div class="flex-item-0"></div>
<div class="flex-item-0"></div>
<div class="flex-item-2"></div>
<div class="flex-item-2"></div>
<div class="flex-item-3"></div>
</div>
CSS
.flex-box{
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
}
.flex-item-0{
order: 0;
}
.flex-item-2{
order: 2;
}
.flex-item-3{
order: 3;
margin-left: auto;
}
and when the flex-box gets less than 500px (or whatever specified amount) I want flex-item-3 to change to:
.flex-item-3{
order: 1;
/*margin-left: auto;*/
}
(I comment out the margin-left: auto; so the it is noted that is has been taken out)
I know there are #media queries however I am not sure how they would apply in this situation.
Does anyone know how to change a CSS style whenever the containing box gets less than a specific width? (CSS solution preferred but fine with JS/jQuery)
With CSS, as you said, you can use media queries.
In this case you would use:
#media (max-width:500px) {
.flex-item-3 {
order: 1;
margin-left: initial;
}
}
CODE SNIPPET:
.flex-box {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
/*---Demo---*/
margin-top: 40px;
border: 1px solid #262626;
/*---Demo---*/
}
.flex-item-0 {
order: 0;
}
.flex-item-2 {
order: 2;
}
.flex-item-3 {
order: 3;
margin-left: auto;
/*---Demo---*/
font-weight: bold;
background-color: tomato;
/*---Demo---*/
}
#media (max-width: 500px) {
.flex-item-3 {
order: 1;
margin-left: initial;
}
}
<div class="flex-box">
<div class="flex-item-0">0</div>
<div class="flex-item-0">0</div>
<div class="flex-item-0">0</div>
<div class="flex-item-2">2</div>
<div class="flex-item-2">2</div>
<div class="flex-item-3">3</div>
</div>