I trying to place a div between divs for a mobile screen.
I don't want to use javascript, just plain css. Is there a way to achieve it?
I'm experimenting with flexboxes order but can't reach my goal.
.parent {
display: flex;
justify-content: flex-start;
}
.left {
background-color: yellow;
padding: 20px;
width: 50%;
}
.left-1 {
background-color: greenyellow;
padding: 20px;
}
.left-3 {
background-color: gray;
padding: 20px;
}
.right {
background-color: cyan;
padding: 20px;
width: 50%;
}
<section class="parent">
<div class="left">
<div class="left-1">1</div>
<div class="left-3">3</div>
</div>
<div class="right">2</div>
</section>
The easiest way to achieve your desired outcome is to use CSS grid layout, which allows for all elements to be siblings, along with a media-query:
/* simple reset to ensure all element sizes are calculated the same way,
and with the same base-styles: */
*,
::before,
::after {
box-sizing: border-box;
font-size: 16px;
font-family: system-ui, sans-serif;
font-weight: 400;
margin: 0;
padding: 0;
}
.parent {
/* using CSS Grid for layout: */
display: grid;
/* setting a gap between adjacent-elements,
(shorthand for 'row-gap' and 'column-gap') */
gap: 0.5em;
/* defining named areas for the contents to be positioned,
based on rows; the first row comprises of one area named:
'leftTop' and the second named 'main'; the second row
has 'leftLower' and 'main'; the reason that 'main' appears
twice is that we want the element in that position to span
across both rows: */
grid-template-areas:
"leftTop main"
"leftLower main";
/* setting height and width to be full-screen: */
width: 100vw;
height: 100vh;
/* setting padding, so that there is a visible gap between the
elements and the page's borders (obviously, adjust to taste): */
padding: 0.5em;
}
/* writing the common styles shared by all child-elements into the same
place for ease of maintenance/updates: */
.parent div {
padding: 20px;
}
/* the left-1 and left-2 elements will be laid out automatically according
to their order in the DOM, once any grid-items (the 'left-1', 'left-2',
and 'right' elements) have been allocated their specific places according
to the author's design: */
.left-1 {
background-color: greenyellow;
}
.left-3 {
background-color: gray;
}
.right {
background-color: cyan;
/* here we explicitly place this element into the named (but not quoted)
main grid-area: */
grid-area: main;
}
/* when the screen falls below 450px in width (obviously adapt to your own
requirements): */
#media screen and (max-width: 450px) {
/* the grid-template-areas are redefined into three single-column rows: */
.parent {
grid-template-areas: "topLeft" "main" "lowerLeft";
}
}
<section class="parent">
<!-- removed the wrapper 'left' column element, in order to allow the
'right' element to be positioned between the 'left-1' and 'left-3'
elements when the screen-size changes: -->
<div class="left-1">1</div>
<div class="left-3">3</div>
<div class="right">2</div>
</section>
JS Fiddle demo.
References:
box-sizing.
display.
font-family.
font-size.
font-weight.
gap.
grid-template-areas.
margin.
#media queries.
padding.
Bibliography:
"A Complete Guide to Grid."
"Basic Concepts of grid layout."
"CSS Grid Layout."
Related
I'm trying to build a portfolio website like this now.
Website Link
Typically when the width of the screen size is less than half of the full width for the website, its content starts to be hidden instead of shrinking. Mine on the other hand, keeps shrinking.
How do I do that with CSS?
It's what I've done so far. I'm using sass and React.js.
App.scss
$main-container-height: 87vh;
$navbar-height: 13vh;
/* Navbar style */
.navbar {
height: $navbar-height;
text-transform: uppercase;
.name {
text-align: left;
margin-left: 1.5rem;
a {
color: black;
font-size: 25px;
margin: 0 0 0 0.5rem;
text-decoration: none;
}
.box {
height: 15px;
width: 15px;
background-color: blue;
display: inline-block;
}
}
.nav-list {
a {
color: black;
margin: 0 1.5rem;
}
a:hover {
color: #519df9;
text-decoration: none;
}
}
}
/* Homepage Style */
.main-box {
height: $main-container-height;
min-width: 50%;
.left-main-box {
height: $main-container-height;
width: 40vw;
display: inline-block;
background-color: #e8c9c9;
}
.right-main-box {
display: inline-block;
height: $main-container-height;
width: 60vw;
background-color: white;
}
}
HomeMain.js
import React, { Component } from "react";
import CenterBox from "./CenterBox";
import Footer from "./Footer";
export class HomeMain extends Component {
render() {
return (
<div className="main-box">
<div className="left-main-box">left</div>
<div className="right-main-box">right</div>
</div>
);
}
}
I'm not sure of what you expect since I can't replicate the problem: decreasing screen width on the link you provided has no shrinking effect for me in Firefox.
That being said:
I recommend that you do you layout for small screens first as it is way easier to do this way rather than the other.
In order to do that you can use grid along with media queries.
For example, you can achieve that using grid-template-areas property, and change this layout using a media query.
Once your template is ok, you can style elements within containers with flex for alignment etc.
Don't forget to use min-width and max-width when using responsive units.
something like that (you get the idea)
/* mobile */
.main-box{
display: grid;
grid-template-areas:
"header"
"nav"
"content"
"footer";
}
/* desktop */
#media screen and (min-width: 1024px){
.main-box{
grid-template-areas:
"header header header"
"nav nav nav"
"leftbox content rightbox"
"footer footer footer";
}
More on grid and flex if you want to practice.
Consider an absolutely positioned <aside> that has a display: grid with grid-template-columns.
I'd expect yellow box appear to the left of the blue box, and both aligned to the right of the container (the black box). Instead, yellow box is placed on top of the blue box.
Also note that adding .fix1 or .fix2 to <aside> makes the grid to lay items in a row, as expected (but break other things).
Why grid items (<span>'s) are placed in a column, not in a row? How to fix this and still position contents using CSS grid? (I'm not interested in Flexbox, floats etc.)
main {
width: 300px;
}
div {
position: relative;
}
section {
width: 100%;
height: 30px;
background-color: black;
}
aside {
position: absolute;
display: grid;
grid-template-columns: repeat(auto-fill, 2em);
top: 0;
right: 5px;
height: 100%;
}
span {
display: block;
}
span:nth-child(1) {
background-color: yellow;
}
span:nth-child(2) {
background-color: blue;
}
/* Adding this class to <aside>
fixes the issue, but aligns
grid contents to the left */
.fix1 {
width: 100%;
}
/* Adding this class to <aside>
fixes the issue, but breaks
the placement of <aside> */
.fix2 {
position: relative;
}
<main>
<div>
<aside class="">
<span>.</span>
<span>.</span>
</aside>
<section/>
</div>
</main>
This is not related to CSS grid but to the shrink-to-fit behavior of absolute element. From the specification we have:
Calculation of the shrink-to-fit width is similar to calculating the width of a table cell using the automatic table layout algorithm. Roughly: calculate the preferred width by formatting the content without breaking lines other than where explicit line breaks occur, and also calculate the preferred minimum width, e.g., by trying all possible line breaks. CSS 2.1 does not define the exact algorithm. Thirdly, calculate the available width: this is found by solving for 'width' after setting 'left' (in case 1) or 'right' (in case 3) to 0.
Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width).
In your case the available width is big enough and the preferred minimum width is the same as the preferred width (the one used) since there is no possible line break.
And if we chech the specification of CSS grid related to auto-fill
When auto-fill is given as the repetition number, if the grid container has a definite size or max size in the relevant axis, then the number of repetitions is the largest possible positive integer that does not cause the grid to overflow its grid container (treating each track as its max track sizing function if that is definite or as its minimum track sizing function otherwise, and taking gap into account); if any number of repetitions would overflow, then 1 repetition. Otherwise, if the grid container has a definite min size in the relevant axis, the number of repetitions is the smallest possible positive integer that fulfills that minimum requirement. Otherwise, the specified track list repeats only once.
Basically you are falling into the last case because the size of the absolute element is the size of its content and we can only place one repetition inside it.
Remove the display:grid to see the size:
main {
width: 300px;
}
div {
position: relative;
}
section {
width: 100%;
height: 30px;
background-color: black;
}
aside {
position: absolute;
grid-template-columns: repeat(auto-fill, 2em);
top: 0;
right: 5px;
height: 100%;
}
span {
display: block;
}
span:nth-child(1) {
background-color: yellow;
}
span:nth-child(2) {
background-color: blue;
}
/* Adding this class to <aside>
fixes the issue, but aligns
grid contents to the left */
.fix1 {
width: 100%;
}
/* Adding this class to <aside>
fixes the issue, but breaks
the placement of <aside> */
.fix2 {
position: relative;
}
<main>
<div>
<aside class="">
<span>.</span>
<span>.</span>
</aside>
<section/>
</div>
</main>
To obtain what you want you can consider a column flow and define each column to be 2em:
main {
width: 300px;
}
div {
position: relative;
}
section {
width: 100%;
height: 30px;
background-color: black;
}
aside {
position: absolute;
display:grid;
grid-auto-columns: 2em;
grid-auto-flow:column;
top: 0;
right: 5px;
height: 100%;
}
span {
display: block;
}
span:nth-child(1) {
background-color: yellow;
}
span:nth-child(2) {
background-color: blue;
}
/* Adding this class to <aside>
fixes the issue, but aligns
grid contents to the left */
.fix1 {
width: 100%;
}
/* Adding this class to <aside>
fixes the issue, but breaks
the placement of <aside> */
.fix2 {
position: relative;
}
<main>
<div>
<aside class="">
<span>.</span>
<span>.</span>
</aside>
<section/>
</div>
</main>
position:relative fix the issue because the width calculation will no more be shrink-to-fit but you will have 100% of the container block width ref so you have enough room for many repetition.
width:100% fix the issue the same way as position:relative because the width will increase to have enough room for more repetition.
So I'm attempting to create the above. Is there a smart way of making the menu component? Or does the container element have to cover most of the content component (it has to be a rectangle and in itself use CSS Grid to position the left part and the top part of the menu)?
This doesn't exactly match your single 'L' shape component requirement, but should get you closer than you were before.
A couple notes worth mentioning:
This simply answers your question as a html/css question, not in React style. You could split this up into two components like you were hoping for by using every html/css element other than body-content, then having body-content html/css as the child
Not sure exactly how you want to handle your content, but with this code the App-Header will scroll with your content. If you want it to be fixed and stay above the content copy the MainMenu's css, but style it for vertical scrolling.
Hope this gets you going in the right direction.
body {
margin: 0px;
}
.App-header {
background-color: #203764;
height: 80px;
padding: 10px;
color: white;
}
/* Style page content */
.main-content {
margin-left: 160px; /* Same as the width of the MainMenu */
}
.body-content {
padding: 20px;
}
/* The MainMenu menu */
.MainMenu {
height: 100%; /* Full-height: remove this if you want "auto" height */
width: 160px; /* Set the width of the sidebar */
position: fixed; /* Fixed Sidebar (stay in place on scroll) */
z-index: 1; /* Stay on top */
top: 0; /* Stay at the top */
left: 0;
background-color: #111; /* Black */
overflow-x: hidden; /* Disable horizontal scroll */
color: #FFF;
}
<div class="App">
<div class="MainMenu">Main Menu</div>
<div class="main-content">
<header class="App-header">Header</header>
<div class="body-content">Content</div>
</div>
</div>
I'm newish to flexbox. My current layout isn't working as well as I'd hoped - my columns are only as tall as the content within them.
+----------------+
| header |
+-+--------------+
|n|content |
|v+--------------+
+-+
empty
----------------------
I'm hoping flexbox will solve that. I'll have to retrofit my existing markup.
Page is full screen width, with a full-width header, then the rest of the page is fluid width content with a fixed width sidebar. (Some pages have a sidebar on the left, others have one on the right.)
Ideally, the two content areas will both extend to the bottom of the page (with their coloured backgrounds) but only go over the fold and scroll if the content is longer than a page.
+----------------+
| header |
+-+--------------+
|n| content |
|a| |
|v| |
--+-+--------------+--
Do I treat the entire page as the "container", in which I create two rows, one of which is split? Or do I just start the flexbox stuff with the second row that has the sidebar?
It seems to me, it has to be the former, if flexbox is to know how high my header is. Otherwise, when I set their heights to 100%, they'll go over the fold by an amount equal to my header.
I didn't see a header-and-split-columns as a simple example in the flexbox docs, but I'll continue to read and experiment.
(Naturally, it will also have to be responsive, so that, at smaller screen sizes, the elements wrap under each other to fit on a narrow screen.)
OK, gathering all the feedback I've gotten above, and borrowing heavily from here, this is what I came up with.
<div class="page-body no-nav no-aside">
<main>
<p>content</p>
</main>
<nav>nav</nav>
<aside>details</aside>
</div>
.
.wrapper {
display: flex;
min-height: 100vh;
flex-direction: column;
background-color: blue;
header {
height: 155px;
}
.page-body {
display: flex;
flex: 1;
background-color: lavender;
flex-direction: column;
min-height: calc(100vh - 155px);
min-height: -webkit-calc(100vh - 155px);
nav {
order: -1;
background-color: red;
}
aside {
background-color: orange;
}
&.no-nav nav,
&.no-aside aside {
display: none;
}
}
}
#media (min-width: 768px) {
.wrapper {
.page-body {
flex-direction: row;
flex: 1;
main {
flex: 1;
}
nav {
flex: 0 0 385px;
}
aside {
flex: 0 0 320px;
}
}
}
}
Header is fixed height
Page-body fills the rest of the page
pretty straightforward to add a footer if needed (see Holy-Grail article above)
all columns are full height, no scrolling unless content flows
sidebars are fixed width, content body is fluid
structure is responsive
added some functionality to hide/show the sidebars as-needed per page
Oddly, this defaults to small-screen as has a media query that overrides for larger screens. (Usually the other way around where I come from.)
You can use calc for the min-height (assuming header height as 50px):
.content {
min-height: calc(100% - 50px);
min-height: -webkit-calc(100% - 50px);
}
As for the fixed width sidebar, prevent it from growing or shrinking:
.sidebar {
flex-shrink: 0;
flex-grow: 0;
}
I would only put the sidebar and the content in the flex box. Put both the sidebar and the content inside a container div and assign display:flex to the container:
.container {
display: flex;
flex-direction: row;
}
You will likely need your sidebar to collapse or become fluid with media queries when the window width decreases to a certain point. Also, I find this tool helpful when working with flex, as it does get complex.
You can create two flexboxes - one to divide header and "rest", and the other inside "rest" to divide it into nav and content.
Also you can just set min-height of header, as can be seen here
I hope I've understood your question.. This approach might help get you started. Let me know if you have any specific questions...
body {
margin: 0;
height: 100vh;
font-family: sans-serif;
color: white;
}
.container {
height: 100%;
background: grey;
display: flex;
flex-direction: column;
}
header {
height: 150px;
background: blue;
}
.content {
height: 100%;
display: flex;
background: green;
}
.sidebar {
background: #76c5ff;
width: 200px;
}
.main {
background: #ef3a59;
flex: 1;
}
#media (max-width: 600px) {
body {
height: initial;
}
.content {
height: initial;
}
.content {
flex-direction: column;
}
.sidebar {
width: 100%;
order: 2; /* remove this to keep sidebar above main content */
}
}
<div class="container">
<header>header
</header>
<div class="content">
<div class="sidebar">sidebar</div>
<div class="main">main content</div>
</div>
</div>
I'm having some issues with creating this effect with CSS:
http://i.stack.imgur.com/sMBmg.jpg
Basically, I want my content div to float on top and slightly overlap both the header and the footer elements. I've played around with some absolute positioning but I'm not sure if that's the best way to go. I want a responsive solution that works for all devices and screen sizes. Any suggestions?
Here is one way you could do it.
If this is your HTML:
<div class="header">Header</div>
<div class="content">Content</div>
<div class="footer">Footer</div>
Apply the following CSS:
.header, .footer {
height: 100px; /* not strictly needed... */
border: 1px solid blue;
}
.content {
width: 50%; /* for example... */
height: 400px;
background-color: yellow;
margin: 0 auto;
border: 1px dotted blue;
}
.header {
margin-bottom: -25px;
}
.footer {
margin-top: -25px;
}
.content {
position: relative;
z-index: 1;
}
You can see the demo at: http://jsfiddle.net/audetwebdesign/CNnay/
You set up three block level elements for the header, content and footer.
Apply negative margins to the bottom of the header and the top of the footer to
create the offset effect.
Finally, apply z-index to .content to tweak the stacking order so that the
content block is painted over the footer block.
In this layout, the content block will expand vertically as you add more content.
The results looks like:
You can try position:fixed or z-index:2000 of your div class
i have created this http://jsfiddle.net/RVnU7/1/