Two-Column Newspaper Layout with CSS Grid - css

I've got CSS grid to produce a two-column layout. But the problem is that it's not top-aligning content in each column.
For example, in the second column, the last element should top-align to but up against the other column-two element.
body>div {
display: grid;
grid-template-columns: 50% 50%;
grid-template-rows: auto auto;
grid-auto-flow: column;
/* https://codepen.io/maddesigns/pen/oZGWRN */
/* https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow */
}
body>div>div:nth-of-type(1) {
height: 300px;
}
body>div>div:nth-of-type(2) {
height: 100px;
}
body>div>div:nth-of-type(3) {
height: 200px;
}
<div style="">
<div style="background:red">
1
</div>
<div style="background:green;">
2
</div>
<div style="background:yellow">
3
</div>
<div style="background:pink">
4
</div>
</div>
I couldn't use flex for this layout because I wanted to achieve this layout without defining the container height. column-count:2 would have worked without defining the container height but then I couldn't use div reordering.
So I'm using CSS grid because div reordering is still available (e.g./i.e. order:–1; works well) and it auto-divies up what to put in each of the two columns.

The gird is acting exactly as intended, to keep order and symmetry just like this. I can recommend using 2 grids side by side to achieve what you're looking for. Here's an example that I made to demonstrate this:
.left{
display: grid;
grid-template-rows: auto auto;
grid-auto-flow: column;
width: 50%;
float: left;
/* https://codepen.io/maddesigns/pen/oZGWRN */
/* https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow */
}
.right{
display: grid;
grid-template-rows: auto auto;
grid-auto-flow: column;
width: 50%;
/* https://codepen.io/maddesigns/pen/oZGWRN */
/* https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow */
}
.left>div:nth-of-type(1) {
height: 300px;
}
.left>div:nth-of-type(2) {
height: 100px;
}
.right>div:nth-of-type(1) {
height: 200px;
}
.right>div:nth-of-type(2) {
height: 50px;
}
<div class="left" style="">
<div style="background:red">
1
</div>
<div style="background:green;">
2
</div>
</div>
<div class="right">
<div style="background:yellow">
3
</div>
<div style="background:pink">
4
</div>
</div>

In fact, until a CSS technology arrives with the ability to automatically close the gaps, CSS in general has no solution. Something like this would probably require reflowing the document, so I'm not sure how useful or efficient it would be.
Source: https://stackoverflow.com/a/45200955/1625909

Related

How to reorder the bootstrap grid system?

I'm new to bootstrap and I've only created grid system with pure css, I'm just learning yet how to use bootstrap. I just want to know how can I make like 20% 80% of the column of the grid and for the second grid (80%) it is something like a two rows which is 50% 50% and the main object is at second column second grid. To understand briefly here is my example. (Additional i don't know where to or what to search about how to reorder in grid system of bootstrap since it doesn't make me understand it very well.)
*,*::after,*::before {
padding:0;
margin:0;
}
.grid-system {
width: 100%;
height: 500px;
display: grid;
grid-template-columns: 20% 80%;
}
.grid-column1 {
background:pink;
}
.grid-column2 {
display:grid;
grid-template-columns:50% 50%;
grid-column: 2/2;
}
.first-column {
grid-column: 0/2;
display: grid;
grid-template-rows: 50% 50%;
}
.grid-row {
display:flex;
align-items:center;
justify-content:center;
background:red;
}
.grid-row:nth-child(2) {
background:green;
}
.second-column {
grid-column:2/2;
display:grid;
background:orange;
display:flex;
align-items:center;
justify-content:center;
}
<div class="grid-system">
<div class="grid-column1">
</div>
<div class="grid-column2">
<div class="first-column">
<div class="grid-row">
1
</div>
<div class="grid-row">
2
</div>
</div>
<div class="second-column">
<div class="main-row">
HERE SOME IMAGES
</div>
</div>
</div>
</div>
Something like this..because I can't get any information about bootstrap reordering a columns or row or something else...It is just teachning the basic stuffs of cols-row and etc blah blah.

CSS - spaces between items on multiple lines [duplicate]

This question already has answers here:
Targeting flex items on the last or specific row
(10 answers)
Closed 1 year ago.
I have a container with a dynamic number of items.
Each line can contain up to 4 items. If there are more than 4 items, the next item will start a new line (image 1). If there are less than 4 items it's OK, they just won't fill the whole line (image 2).
But I'm having troubles with the spaces between them:
I tried to use margin-right but it affects the last items in the lines (e.g.: item #4).
I tried to use justify-content: space-between but it looks good only for 4 items and up. For 3 and bellow, it creates a big space between them and I want them to look as in image 2.
Any other elegant / easy solutions?
.container {
display: flex;
flex-wrap: wrap;
/* justify-content: space-between; */
}
.item {
display: inline-block;
width: calc(25% - 12px);
/* margin-right: 12px; */
}
<div class="container">
<div class="item">
#1
</div>
<div class="item">
#2
</div>
<div class="item">
#3
</div>
<div class="item">
#4
</div>
</div>
You can use css grid, you have to use display: grid;, use grid-template-columns to set the amount of columns that you want (1fr = 1 parent container fraction) and finally use grid-gap to set the space between your items.
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-gap: 12px;
}
.item {
display: inline-block;
border: 1px solid red;
color: red;
}
<div class="container">
<div class="item">
#1
</div>
<div class="item">
#2
</div>
<div class="item">
#3
</div>
<div class="item">
#4
</div>
</div>
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-gap: 12px;
}
.item {
display: inline-block;
border: 1px solid red;
color: red;
}
<div class="container">
<div class="item">
#1
</div>
<div class="item">
#2
</div>
<div class="item">
#3
</div>
<div class="item">
#4
</div>
<div class="item">
#5
</div>
<div class="item">
#6
</div>
</div>
More info about Css grid Here!
In class .item, is defined width with calc(25% - 12px). Remember, 25% is just 4 items in each line. 20% is 5 items in each line.
So, change the width to calc(20% - 12px)
While CSS Grid is possibly the better solution for the problem, it's entirely possible to solve the problem with CSS flex-box layout, using the gap property and taking advantage – as did your original code – of the calc() function:
// this is to allow you to dynamically add more .item elements
// so you see that it should meet your needs containing more
// elements.
// we use document.querySelector() to retrieve the first element
// that matches the selector (if any exist, otherwise null):
const button = document.querySelector('button'),
// defining a named function to handle addition of new .item
// elements:
addMore = () => {
// finding the first .item element on the page:
let base = document.querySelector('.item');
// finding the .container element, and using
// .append() to attach a cloned copy of the first
// .item:
document.querySelector('.container').append(base.cloneNode(true));
}
// binding the named - addMore() - function as the event-handler
// for the 'click' event:
button.addEventListener('click', addMore);
*,
::before,
::after {
/* selecting all elements, and the pseudo-elements ::before
and ::after, setting their box-sizing model to border-box
in order that their widths include their border and padding
*/
box-sizing: border-box;
/* removing margin and padding: */
margin: 0;
padding: 0;
}
.container {
display: flex;
flex-wrap: wrap;
/* using the gap property to place a 0.5em 'gutter'
between adjacent elements, both horizontally and
vertically: */
gap: 0.5em;
}
.item {
/* setting the flex-grow: to 1, flex-shrink to 0,
and flex-basis to the result of 20% of the parent-
width minus 0.5em (the gap-space): */
flex: 1 0 calc(20% - 0.5em);
}
/* irrelevant, purely for aesthetics */
*,
::before,
::after {
line-height: 2em;
}
.container {
border: 1px solid #000;
counter-reset: itemCount;
width: 90vw;
margin-inline: auto;
}
.item {
background-color: lightblue;
flex: 1 0 calc(20% - 0.5em);
}
.item:nth-child(odd) {
background-color: palegreen;
}
.item::before {
content: counter(itemCount, decimal-leading-zero);
counter-increment: itemCount;
}
<button type="button">Add another item</button>
<div class="container">
<div class="item">
</div>
<div class="item">
</div>
<div class="item">
</div>
<div class="item">
</div>
</div>
JS Fiddle demo.
References:
box-sizing.
calc().
gap.
margin-inline.

Scaling and aligning a simplistic website with image content

I am working on a simplistic website to show pictures in a single stream. To keep javascript to a minimum (just lazy loading), I only use a single relatively high-resolution version of each image and then rely on CSS to resize.
My question is how the rest of the website, at least the logo and the menu, can be best resized relative to the size of the images. After reading the CSS grid guide I decided to use a grid with grid-auto-flow: row.
The problem: I want the logo to flush left with the left of the top image and the menu to flush right with the right of the top image (all horizontal images have the same width).
My current code either aligns logo and menu to the corners of the page (as with the code below) or centers both (if I move the header into the grid as first item)
#main{
height: max-content;
display: grid;
grid-auto-flow: row;
grid-row-gap: 8em;
place-items: center center;
}
.photo_horizontal, .photo_vertical{
object-fit: contain;
height: auto;
}
.photo_horizontal{
width: 80vw;
max-height: 80vh;
}
.photo_vertical{
width: 60vw;
max-height: 90vh;
}
/* THE HEADER */
header{
display: grid;
grid-auto-flow: column;
}
#logo{
width: 15em;
justify-self: start;
}
header > div{
margin: auto 0 0 auto;
}
<header>
<img id="logo" src="https://via.placeholder.com/500x100/ff7f7f/333333?text=some%20website"/>
<div>
menu1
menu2
</div>
</header>
<div id="main">
<img class="photo_horizontal" src="https://picsum.photos/3000/2000"/>
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_horizontal" src="https://picsum.photos/3000/2000" />
</div>
Is there an elegant way to resize images relative to the viewport but still align other content accordingly? I tried to pad logo and menu left/right but the necessary padding depends on the actual size of the image.
A pen can be found here.
To clarify, this is how it currently is and this is what I want.
The main problem is setting .photo_horizontal's .max-height: 80vh; causes it to not always honor the width: 80vw; which means the width of the .photo_horizontal is not easily calculated. That makes it difficult to make the <header> the same width.
You can do this:
header {
width: 80vw;
margin: auto;
}
But it only works if you also get rid of the max-height: 80vh rule for .photo_horizontal.
https://codepen.io/km0ser/pen/LYpqeYB
Why not include the header within #main
/* Nothing wrong with CSS grid, just Flexbox is simpler */
#main {
display: flex;
flex-direction: column;
align-items: center;
border: 1px solid;
}
/* height being auto will keep the aspect ratio */
/* horizontal photo take full width */
.photo_horizontal {
max-width: 100%;
}
/* horizontal photo take some portion of width */
.photo_vertical {
max-width: 80%;
}
header {
display: flex;
width: 100%;
}
#logo {
width: 15em;
}
header>div {
margin: auto 0 0 auto;
}
<div id="main">
<header>
<img id="logo" src="https://via.placeholder.com/500x100/ff7f7f/333333?text=some%20website" />
<div>
menu1
menu2
</div>
</header>
<img class="photo_horizontal" src="https://picsum.photos/3000/2000" />
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_horizontal" src="https://picsum.photos/3000/2000" />
</div>
Thanks to the answers here I figured out a solution. There are three components:
As #Zohir Salak pointed out, much simpler CSS can be obtained using flexbox.
The header can be part of main even though this is not essential to the solution.
As #kmoser pointed out, the max-height constraint on images makes it hard to set a proper max-width constraint for the header, a problem that isn't solved by 1. and 2. yet. However, since all of my pictures are 3:2 ratio, a max-height constrained can be turned into a max-width constrained easily and then combined with a min via max-width: min(80vw, 3 / 2 * 80vh);.
/* Nothing wrong with CSS grid, just Flexbox is simpler */
#main {
display: flex;
flex-direction: column;
align-items: center;
border: 1px solid;
}
/* height being auto will keep the aspect ratio */
/* horizontal photo take full width */
.photo_horizontal {
max-width: min(80vw, 3 / 2 * 80vh);
}
/* horizontal photo take some portion of width */
.photo_vertical {
max-width: min(80vw, 2 / 3 * 80vh);
}
header {
display: flex;
width: 100vw;
max-width: min(80vw, 3 / 2 * 80vh);
}
#logo {
width: 15em;
}
header>div {
margin: auto 0 0 auto;
}
<div id="main">
<header>
<img id="logo" src="https://via.placeholder.com/500x100/ff7f7f/333333?text=some%20website"/>
<div>
menu1
menu2
</div>
</header>
<img class="photo_horizontal" src="https://picsum.photos/3000/2000"/>
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_horizontal" src="https://picsum.photos/3000/2000" />
</div>
Alternatively, see the same code in a pen here.

Make flex item with flexible size keep its size when children overflow [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 5 years ago.
This one is really frustrating me and Im not sure if I worded that correctly.
Basicly, I need my page to stay at 100% height and not grow in height as it is a single page website.
I have a list in an aside and whenever I add content to the list it makes the list grow in size when I need the overflow to be hidden (I have a custom scrollbar applied in react).
Anyhow, the growing (weirdly) only occures when the list has the height of flex: 1;. When I add a fixed height, everything is fine.
Here is how it acts with a fixed height (should also be like this when no fixed height is applied):
When I remove the fixed height of the red box (the list) then it causes itself and the whole page to grow:
See it in action:
Heres the pen to see for yourself: https://codepen.io/anon/pen/zPJdoK
I know theres some unnecassary markup but I needed that to be sure that it represents the actual webpage I am working on.
Sorry for not being able to explain it any more detailed, Im a bit confused as of now...
Are you referring to something like this perhaps? I'm not too sure.
.container{
background: black;
width: 1000px;
height: 300px;
display: grid;
grid-template-columns: 180px 1fr 180px;
grid-template-rows: 1fr;
grid-template-areas: "nav main aside";
}
nav {
grid-area: nav;
background: blue;
}
main {
grid-area: main;
background: black;
display: flex;
flex-direction: column;
}
aside {
grid-area: aside;
background: green;
display: flex;
flex-direction: column;
}
aside > header, aside > footer{
height: 60px;
background: yellow;
}
aside > main {
flex: 3;
background: green;
}
aside > main > .content {
background: red;
margin: 10px;
max-height: 200px;
overflow-y:scroll;
}
.space_taker{
margin: 10px;
height: 30px;
background: white;
}
<div class="container">
<nav></nav>
<main></main>
<aside>
<header>
</header>
<main>
<div class="content">
<div class="space_taker">asdafasdfasdf</div>
<div class="space_taker">asdfasdf</div>
<div class="space_taker">asdfs</div>
<div class="space_taker">dfgdgf</div>
<div class="space_taker">asdasd</div>
<div class="space_taker">asdasd</div>
<div class="space_taker">asdfs</div>
<div class="space_taker">dfgdgf</div>
<div class="space_taker">asdasd</div>
<div class="space_taker">asdasd</div>
<div class="space_taker">asdfs</div>
<div class="space_taker">dfgdgf</div>
<div class="space_taker">asdasd</div>
<div class="space_taker">asdasd</div>
</div>
</main>
<footer>
</footer>
</aside>
</div>

Using calc() with a dynamic value?

I am wondering if this is possible: I have a header that can contain a variable amount of text. Below that I have another element which I want to take up the remaining height of the page.
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
Normally I would do this using calc, eg:
.content {
height: calc(100vh - 75px);
}
Where 75px is the set height of .header.
But in this example, the .header element is dynamic and does not have a set height. Only a padding and font-size are set.
To complicate things, this also uses the Foundation Grid layout, which makes me nervous about using display: table (.title and .menu sit side by side on desktop, but stacked on mobile) .
Is there anyway to get the height of the dynamic header element (without resorting to JQuery)?
You can use flexbox and set .content to flex-grow: 1 so that it will fill to grow the available space.
body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
.content {
flex-grow: 1;
background: #eee;
}
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
I made a small pen to show the way to do this using flex box, it involved changing your markup a bit:
css:
.container {
display: flex;
flex-direction: column;
height: 250px; // whatever you want here
}
.header {
width: 100%;
background: red;
padding: 10px;
}
.content {
background: yellow;
width: 100%;
flex-grow: 1;
}
So the content will always take the available space inside the content div.
check the whole pen: http://codepen.io/anshul119/pen/yMYeLa
hope this helps.

Resources