The easiest way to understand what I want to achieve is in the attached image.
Essentially, I want to create a responsive layout comprising of 3 elements within a section - a header, a body, and a footer. On smaller screens (i.e. mobile) the 3 elements simply stack as you'd expect.
However, on larger desktop screens, I want the elements to split into 2 columns - the header and footer on the left, and the body on the right.
The problem is I'm actually not sure I can create this behaviour with CSS alone.
The best I can achieve ends up with the footer element staying in line with the bottom of the body element, like the below image (I understand why, I just want to figure out a way around this.)
I've tried a few methods using floated elements, as well as flexbox solutions and playing with the ordering, but with no success. I even tried some grid stuff, although my knowledge of grid isn't great so I may have missed something.
I know that I could use JS to do something such as moving the header and footer within a single parent element, or back out again, depending upon screen size. But I'm hoping there's a CSS-only way to achieve this, as that doesn't seem very elegant.
Thanks in advance for any suggestions!
Use css-gridwith the use of `grid-template-areas" to define the placement of a specific section as the example below. To allow the body section to extend further then the header and footer, you just need to use 3 rows.
body {
display: grid;
margin: 0;
padding: 20px;
grid-gap: 20px;
}
section {
background-color: red;
color: white;
padding: 10px;
}
#header {
grid-area: header;
}
#body {
grid-area: body;
}
#footer {
grid-area: footer;
}
#media only screen
and (max-width: 480px) {
body {
grid-template-areas:
"header"
"body"
"footer";
}
}
#media only screen
and (min-width: 481px) {
body {
grid-template-areas:
"header body"
"footer body"
". body";
grid-template-columns: 4fr 6fr;
}
}
/* for styling purpose only */
#body {
min-height: 70vh;
}
<section id=header>Header</section>
<section id=body>Body</section>
<section id=footer>Footer</section>
I have used CSS Grid to achieve this, I know you already acheived in Mobile version so I'm just sharing the demo code for Desktop Version. CSS Grid is really powerful you can create complex layout in minutes.
.outer{display: grid; grid-template-areas: 'header body' 'footer body' 'footer body';
}
.header{width: 100%; grid-area: header; height: 50vh; background-color: yellow;}
.body{grid-area: body; background-color: red; }
.footer{grid-area: footer; height: 50vh; background-color: violet;}
<div class='outer'>
<div class='header'> HEADER</div>
<div class='body'> body</div>
<div class='footer'> Footer</div>
</div>
using a div with zero width and height and margin negative of the div the result can be achieved.
the purple is a div with display flex and a normal
orientation with flex wrap turned on. orange is the footer. it has a
negative margin to equivalent to the body height plus the. the thing in yellow
is a div with width and height 0 and margin bottom equivalent to its height
of the body. when the page is wide enough both the body and and the yellow
div are moved to the side and the negative margin of the footer makes it go up to just
bellow the header at the bottom is an in browser version, the yellow square is there to indicate
the location of the padding div.
I know we are in 2021, but old good simple floats can be used for this task
#media (min-width: 480px) {
div {
display: flow-root;
border: 1px #ccc dashed;
}
header, footer {
width: 40%;
float: left;
}
main {
float: right;
width: calc(60% - 10px);
}
}
div > * {
box-sizing: border-box;
color: #fff;
background: #eb0022;
padding: 10px;
margin-bottom: 10px;
}
<div>
<header>header</header>
<main>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eos tempore doloremque, illum praesentium atque cumque nulla, dolorum obcaecati quod recusandae itaque pariatur unde soluta blanditiis repudiandae perspiciatis deserunt fuga commodi.</p>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eos tempore doloremque, illum praesentium atque cumque nulla, dolorum obcaecati quod recusandae itaque pariatur unde soluta blanditiis repudiandae perspiciatis deserunt fuga commodi.</p>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eos tempore doloremque, illum praesentium atque cumque nulla, dolorum obcaecati quod recusandae itaque pariatur unde soluta blanditiis repudiandae perspiciatis deserunt fuga commodi.</p>
</main>
<footer>footer</footer>
</div>
Related
i've been trying to make the text div to take the entire width of the grid layout but have it's content in line with the rest of the layout itself
I've used width: 100vw, tried padding the corners yet it doesn't work properly and is a bit clunky.
I've uploaded it to the codepen for better understanding
https://codepen.io/Aegtar/pen/PoObBdG
what is needed is that the green part will take the entire width yet the text inside will stay within the lightsalmon div.
the HTML :
<div class='main-layout'>
<div class='weather-page'>
<div class='top-side'>
<div>WeatherPage</div>
<div class='text-container'>
<div class='ha'>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Repellat expedita molestiae nisi dolorum est,
tempore dolore! Itaque quidem nobis deleniti! Lorem ipsum dolor sit amet.
</div>
</div>
<button>
2
</button>
<button>
2
</button>
</div>
</div>
</div>
<section class='footer'>Footer</section>
</div>
the scss :
.main-layout {
display: grid;
grid-template-columns: minmax(10px, 1fr) minmax(auto, 1300px) minmax(10px, 1fr);
> * {
grid-column: 2;
}
> *.full {
grid-column: 1 / -1;
}
}
.home-page {
margin: 0 auto;
display: flex;
flex-direction: column;
width: 50%;
justify-content: center;
align-items: center;
gap: 40px;
}
.weather-page {
gap: 10px;
grid-auto-flow: column;
background-color: lightsalmon;
.top-side {
gap: 20px;
align-items: center;
flex-direction: column;
display: flex;
margin-bottom: 30px;
.text-container {
background-color: lightgreen;
.ha {
text-align: center;
}
}
}
.footer {
background-color: rgb(25, 118, 210);
}
any help is appreciated!
Just remove the grid-template-columns:minmax(10px, 1fr) minmax(auto, 1300px) minmax(10px, 1fr);
from the .main-layout and then add
body{
padding:0;
margin:0;
}
so that it can strech all the way.
Also, if you want the grid-template-columns , then comment on this post and I will (probably) find another solution.
Code Pen: https://codepen.io/576031/pen/rNYWqbz
It seems like you're not really using your grid. You're creating 2 empty columns on the sides for styling and putting all the content in the center column. Why not use the default layout with a simple container and recreate what you want just by using the basic stylings with width, margin and padding.
* { margin: 0 auto; }
.width-90 { width: 90%; }
.width-100 { width: 100%; }
article {
text-align: center;
max-width: 1300px;
border: solid 1px black;
}
article > * { padding: 10px 0 30px 0; }
article header, article section { background-color: lightsalmon; }
article main { background-color: lightgreen; }
article footer { background-color: lightblue; }
/*SCSS was not supported in this snippet but you could remove the word article in the lines above and then just place them in article if you want it to be specific with SCSS*/
<div class='main-layout'>
<article class='weather-page'>
<header class="header width-90">
<h2>WeatherPage</h2>
</header>
<main class='main width-100'>
<p class="width-90"> Lorem ipsum dolor sit amet consectetur adipisicing elit. Repellat expedita molestiae nisi dolorum est, tempore dolore! Itaque quidem nobis deleniti! Lorem ipsum dolor sit amet consectetur adipisicing elit. Iste, at. Atque alias modi nam provident quam, consectetur unde sunt exercitationem corrupti veritatis ea, itaque sint vero voluptatibus in fugit delectus recusandae eos enim deleniti doloribus magni. Repudiandae obcaecati blanditiis temporibus, vitae numquam illum ducimus voluptates sed in repellat quis esse! Cupiditate facilis magni velit molestias iure enim optio ratione. Ad? </p>
</main>
<section class="section-buttons width-90">
<p><button>2</button></p>
<p><button>2</button></p>
</section>
<footer class='footer width-100'>
<p class="width-90">Footer</p>
</footer>
</article>
</div>
If you really want to keep your html structure the way it is then you could probably use a variable since you're working with SCSS. You could try this for example:
$grid-sides: 10px;
.main-layout {
display: grid;
grid-template-columns: minmax($grid-sides, 1fr) minmax(auto, 1300px) minmax($grid-sides, 1fr);
/* ... everything else ...*/
}
/* at the right place in your SCSS*/
.text-container {
margin-left: -$grid-sides;
margin-right: -$grid-sides;
padding-left: $grid-sides;
padding-right: $grid-sides;
background-color: lightgreen;
/* ... everything else ...*/
}
Hello I have a parent flex box and 2 childs with 100% width.
<div class="wrapper">
<app-user></app-user>
<div class="text">
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Delectus
laboriosam incidunt necessitatibus optio id cumque velit nam deserunt
dolorem. Dolorum asperiores corporis reiciendis veniam, porro temporibus
obcaecati distinctio illo. Nihil.
</div>
</div>
My margin in <app-user> not working , due to the 100% width of parent. I need to fix the 100% width of my .sidebar element to keep the width and also I need a margin to take .text little bit away from my first element
link to code
app-user
<div class="sidebar">
sidebar
<img
src="https://cdn.oneesports.gg/wp-content/uploads/2020/07/Dota2_InvokerHeader-1024x683.jpg"
alt=""
/>
</div>
css
.wrapper {
display: flex;
}
.sidebar {
max-width: 400px;
width: 100%;
margin-right: 32px;
}
.sidebar img {
width: 100%;
height: auto;
}
UPD 1
If I move styles from .sidebar directly to app-user in browser it works perfect , but I dont want to use :host styles in css. As in produciton I have a big project
You can use calc() function documented here :
https://developer.mozilla.org/fr/docs/Web/CSS/calc()
So you can remove the margin from your .sidebar class
and add this css lines to your app.component.css :
.wrapper .text { width: calc(100% - 32px); margin-left: 32px; }
And here is your link code that I modified
The weblink is escreva.in , on the phone browser it dose not load images, but the desktop version has no issue in loading the images. Any suggestion??
Daksh.
The Image is a 'background-image' - and the a (link) that has the background image - has no 'shape' - and so, there's nothing to be the background image of (when it's a smaller screen).
When it hits a break-point then the parent is given display:flex - and that just happens to force the link to have a shape that allows for the background image. It's a fluke.
There are many ways to do this differently - but I'm not sure what to suggest for you.
I suggest you write it differently and ditch that framework:
/* global */
img {
display: block;
width: 100%;
height: auto;
}
picture {
display: block;/* inline by default */
}
/* module */
.example-parent {
display: flex;
flex-direction: column;
}
#media (min-width: 600px) {
.example-parent {
flex-direction: row;
align-items: center;
}
.text {
padding-left: 30px;
}
}
<section class="example-parent">
<picture>
<img src="https://placehold.it/1200">
</picture>
<div class="text">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa vero iste quisquam illo autem harum labore, quia maxime quo suscipit natus delectus deleniti impedit ad ipsum ipsam perspiciatis magni corrupti.</p>
</div>
</section>
Example that you can stretch and see in action: https://jsfiddle.net/sheriffderek/6w3s8vg0/
I'm picking up website building after a long vacation (~5 years). CSS standards have changed, and I'm still trying to catch up.
Anyway, I'm still very strict on the quality of my html and will not compromise on that for layouting.
Here's my HTML. It can't change, except for the image-right and image-left classes. Those can be replaced by class="right" or class="left" on the corresponding images.
<div class="text-block image-left">
<h2>A block of text with image on the left</h2>
<img src="https://picsum.photos/300/200" alt="A nice picture" />
<p>
This is one paragraph.
</p>
<p>
This is the second paragraph.
</p>
</div>
<div class="text-block image-right">
<h2>A block of text with image on the right</h2>
<img src="https://picsum.photos/300/200" alt="A nice picture" />
<p>
This is one paragraph.
</p>
<p>
This is the second paragraph.
</p>
</div>
The HTML above reflects how I want it to display on a mobile browser: one column with header, image, and then text.
However, on a desktop browser, I want to make it look like this (well, roughly anyway):
What's the appropriate CSS to achieve that layout without altering the HTML, and having a responsive layout?
CSS Grid is awesome, but for this your best bet would be to use Flexbox and it would be good for accessibility to use some semantic HTML5 too.
For your HTML:
<figure class="image-left">
<img src="https://picsum.photos/300/200" alt="A nice picture" />
<figcaption>
<h2>A block of text with image on the left</h2>
<p>This is one paragraph.</p>
<p>This is the second paragraph.</p>
</figcaption>
</figure>
<figure class="image-right">
<img src="https://picsum.photos/300/200" alt="A nice picture" />
<figcaption>
<h2>A block of text with image on the right</h2>
<p>This is one paragraph.</p>
<p>This is the second paragraph.</p>
</figcaption>
</figure>
And for your CSS:
/* Add styling here you wish to add for screens with a width less than 600px */
#media screen and (min-width: 600px) {
/* Add styling here you wish to add for screens with a width of 600px and wider */
figure {
display: flex;
}
figcaption {
width: 100%;
}
.image-left {
flex-direction: row-reverse;
}
.image-right {
/* This is set to flex-direction: row; by default so doesn't need to be added */
}
}
Any problems or need extra help feel free to comment below :)
Here is a way to do it with grid.I only modified the html by adding a class mobile in your text-block divs to get equal specificity for the #media rules (and avoid duplicate CSS).
/* here I define a 4x3 grid */
/* rows are set to auto so the ones not used will collapse */
div.text-block {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows : repeat(4, auto); }
/* here I tell the h2 for .image-left to start a col2 and use 2 columns */
/* each column is 1fr, so 2 columns is 2/3 of the available space */
div.text-block.image-left h2 {
grid-column: 2 / span 2;
}
/* I don't need to position each "p" on rows, just tell them which
column to go to */
/* no need to put them in a div */
div.text-block.image-right p {
grid-column: 1 / span 2; }
/* I use this code to make your image resize automatically,
but there is plenty of choice to make it look the way you want.
You can also check out the "object-fit" property */
div.text-block.image-left img {
display: block;
height: auto;
max-height: 100%;
max-width: 100%; }
/* for the #media rules I needed a .mobile class to have the same specificity
as the first rule (edit : though removing ".text-block" for "p" and "h2"
declarations would have the same effect) */
/* also needed to re-use "justify-self" on images
as it has priority over justify-items */
#media screen and (max-width: 900px) {
/* all blocks */
div.text-block.mobile h2 {
grid-column: 1 / span 3;
}
You can play with grid-template-columns, grid-template-rows to find the "right" proportions for what you need (for example : grid-template-rows: .2fr repeat(2, 1fr) auto;).
If you have questions, I'll be happy to answer them (or try to at least) ;)
html {
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-size: 16px;
}
*,
*::after,
*::before {
-webkit-box-sizing: inherit;
box-sizing: inherit;
}
img,
p,
h2,
div {
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
min-height: 100vh;
}
div.text-block {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(4, auto);
/*grid-template-rows: .2fr repeat(2, 1fr) auto;*/
align-items: start;
justify-items: left;
}
/* first block */
div.text-block.image-left h2 {
grid-column: 2 / span 2;
}
div.text-block.image-left p {
grid-column: 2 / span 2;
width: 100%;
}
div.text-block.image-left img {
display: block;
height: auto;
max-width: 100%;
grid-column: 1 / span 1;
grid-row: 1 / span 3;
}
/* 2nd block */
div.text-block.image-right h2 {
grid-column: 1 / span 2;
}
div.text-block.image-right p {
grid-column: 1 / span 2;
width: 100%;
}
div.text-block.image-right img {
display: block;
height: auto;
max-width: 100%;
grid-column: 3 / span 1;
grid-row: 1 / span 3;
justify-self: right;
}
/* just to show what's going on */
h2 {
background: blue;
}
p {
padding: 5px;
border: white 1px solid;
background: black;
color: white;
}
div.text-block {
background: white;
border: 2px solid green;
}
/* media query */
#media screen and (max-width: 900px) {
/* all blocks */
div.text-block {
justify-items: center;
}
div.text-block.mobile h2,
div.text-block.mobile p {
grid-column: 1 / span 3;
}
div.text-block.mobile img {
grid-column: 1 / span 3;
grid-row: 2 / span 1;
justify-self: center;
}
}
<div class="text-block mobile image-left">
<h2>A block of text with image on the left</h2>
<img src="https://picsum.photos/600/400" alt="A nice picture" />
<p>
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quaerat quas eius, ab corporis architecto quam? Soluta, reprehenderit eveniet porro fugiat ratione voluptatum harum ea fuga facilis ad incidunt cumque maiores. Lorem ipsum, dolor sit amet consectetur
adipisicing elit. Eos libero illo repellat sint in culpa itaque est modi, eum officia a laborum iure alias cupiditate tenetur, cumque dolorem deleniti? Eum!
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi amet quaerat facere maiores sequi velit totam praesentium adipisci provident aspernatur at commodi, nostrum voluptates esse reiciendis optio rem et impedit!Eveniet ipsa delectus voluptate suscipit
possimus totam qui iusto consectetur sapiente maiores culpa alias, unde enim laudantium libero, consequatur explicabo adipisci non! Non quis optio fugiat, ullam dolorem iure debitis?
</p>
</div>
<div class="text-block mobile image-right">
<h2>A block of text with image on the right</h2>
<img src="https://picsum.photos/600/400" alt="A nice picture" />
<p>
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quaerat quas eius, ab corporis architecto quam? Soluta, reprehenderit eveniet porro fugiat ratione voluptatum harum ea fuga facilis ad incidunt cumque maiores. Lorem ipsum, dolor sit amet consectetur
adipisicing elit. Eos libero illo repellat sint in culpa itaque est modi, eum officia a laborum iure alias cupiditate tenetur, cumque dolorem deleniti? Eum!
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi amet quaerat facere maiores sequi velit totam praesentium adipisci provident aspernatur at commodi, nostrum voluptates esse reiciendis optio rem et impedit!Eveniet ipsa delectus voluptate suscipit
possimus totam qui iusto consectetur sapiente maiores culpa alias, unde enim laudantium libero, consequatur explicabo adipisci non! Non quis optio fugiat, ullam dolorem iure debitis?
</p>
</div>
Edit :
grid-template-rows: repeat(auto-fit, minmax(50px, 1fr));
This is a way to create rows automaticaly if you want to add paragraph and not change the template.
But there are 2 drawbacks :
A height which do not adjust to the content must be defined (not auto, max-content ...etc)
For now I don't know how to make the image "span" all the "not collapsed rows" automatically. So you will need to increment the span for 'grid-row: 1 / span 3;' for the image each time you add a 'p'
I have three div tags, 1 parent and 2 child. The parent div should take up full width of the page and height of the content (i.e. the 2 child divs). The 2 child divs should be positioned horizontally on bigger screens (i.e.) laptops, desktops...) and occupy 50% of the width of parent and expand as per content.
The 2 child divs should align/stack vertically on smaller devices (i.e. mobile), taking up full width of the parent and expand as per of content.
I have tried playing around with the display properties including block, inline-block and position absolute and relative with no luck.
.parent {
display: flex;
padding: 20px;
}
.child1 {
display: inline-block;
width: 50%;
}
.child2 {
display: inline-block;
width: 50%;
}
Use a media query at the moment you want to break down the two child divs to occupy 50% of the width:
Media queries are useful when you want to modify your site or app depending on a device's general type (such as print vs. screen) or specific characteristics and parameters (such as screen resolution or browser viewport width).
MDN resource
#media screen and (min-width: 600px) {
// Add your styling here.
}
See below example for the code.
#media screen and (min-width: 600px) {
.parent {
display: flex;
}
.child {
width: 50%;
}
}
// Color styling
.parent {
background-color: #ccc;
}
.child {
background-color: lightblue;
}
.child:last-child {
background-color: lightgreen;
}
<div class="parent">
<div class="child">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime reprehenderit modi corporis veritatis iste sit, numquam hic velit dolorem recusandae commodi blanditiis animi quisquam temporibus illum id, repellat saepe adipisci eos odit obcaecati atque?
Nihil expedita ab doloribus cum, iusto suscipit autem quos tempore officiis nesciunt maiores. Quos, labore eum perferendis cupiditate veritatis excepturi, tenetur quasi perspiciatis eius suscipit distinctio inventore adipisci asperiores incidunt numquam
fugiat autem minus quae. Possimus fugiat eos consequuntur iusto et nisi earum obcaecati qui accusantium tenetur totam animi debitis minima accusamus cum quas, amet architecto quam sequi quisquam eum dolorum exercitationem rerum adipisci, esse! Voluptates.</div>
<div class="child">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus, enim reprehenderit asperiores sapiente blanditiis odit. Possimus vel porro in eligendi vitae officiis placeat odit asperiores illo consequatur, quos enim nam quam natus pariatur,
sed autem excepturi temporibus, consequuntur beatae eos. Exercitationem voluptatum, aliquam harum delectus provident laudantium perferendis atque aliquid!</div>
</div>
flex and grid can let you drop the mediaquerie breaking point.
With a mediaquerie, you can switch back to display:block;
For infos : Since you use flex on the parent, display value on the children will have no effects but width:50% can be too much if margins, padding or borders are involved. box-sizing can be your friend here.With flex, you can use flex:1; to spray evenly the children , no matter the number, borders, padding or margin.
examples with grid, flex and a switch back to block via a mediaquerie .breakpoint is set at around 620px in the demo , update the value(s). used to fit your needs.
/* the flex container without mediaquerie */
div[class] {
display: flex;
min-height: 20vh;
flex-wrap: wrap;
/* needed to stack children once to big */
}
div[class] div {
flex: 1;
min-width: 300px;
/* 2 children + margin and borders makes a break point at around 620px */
background: lightblue;
}
div div {
border: solid;
margin: 3px;
background: tomato;
}
div[id] {
min-height: 20vh;
display: grid;
grid-gap: 3px;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
/* again a break point at about 620px when 2 children no need of mediaquerie */
}
div[id][class] div {
background: lightgreen;
}
/* remove the grid system at about 620px */
#media screen and (max-width: 621px) {
div[id],
div[class] {
min-height: 30vh;
/* has a meaning with a grid system */
}
div[id][class] {
display: block;
/* looses the grid system, back to classic layout see min-height behavior not resizing children */
border: solid;
}
}
<div class>
<div>1</div>
<div>2</div>
</div>
<div id>
<div>1</div>
<div>2</div>
</div>
<div id class>
<div>1</div>
<div>2</div>
</div>
a few usefull links:
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
https://css-tricks.com/snippets/css/complete-guide-grid/
https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing
https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries
Try using css grid styling to do this. This is a sample code where the child1 and child2 are in the same row in a large screen but when the screen becomes smaller (mobile view) it will be one below the other. Hope it helps you
.parent {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
padding: 20px;
}
<div class="parent">
<div>
child1
</div>
<div>
child2
</div>
</div>
`
.parent {
display: flex;
flex-flow: row wrap;
padding: 20px;
background: #ccc;
box-sizing: border-box;
}
.child {
max-width: 98%;
flex: 0 0 98%;
height: 200px;
background: #333;
margin: 0 1% 10px;
}
#media (min-width: 480px) {
.child {
max-width: 48%;
flex: 0 0 48%;
margin-bottom: 0;
}
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
`