Fixed content and scrolling sidebar, converting grid to flexbox - css

I'm trying to make a layout with a fixed navbar, a fixed-size content area, and a scrollable sidebar. This is a pretty standard setup (though usually the sidebar is fixed while the content scrolls, but that's just semantics), but it's important that the content's box doesn't overflow the overall container, since I'm filling it with an image that gets an object-fit applied so it can scale happily within the viewport while maintaining its aspect ratio.
I actually have a functioning version of it using grid (embedded and linked below). The problem there is that if I want the sidebar to go away, I have to change the styling on the parent divs, which is messy (but doable) in the component system I'm using. Ideally I'd be able to simply set the sidebar to display: none and the content would fill the space.
I've tried converting the whole thing to flexbox, and making the second row into a nested grid, but I can't seem to do either of those while retaining the overall height lock.
Here's the working grid (and a CodePen).
html,
body {
margin: 0;
}
.wrapper {
height: 100vh;
display: grid;
grid-template-columns: 1fr 150px;
grid-template-rows: auto 1fr;
}
nav {
height: 50px;
grid-row: 1;
grid-column: 1 / span 2;
background-color: darkseagreen;
}
.content {
background-color: salmon;
position: relative;
}
img {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
object-fit: contain;
}
.sidebar {
overflow-y: scroll;
background-color: cornflowerblue;
}
<div class="wrapper">
<nav>Navbar should stay fixed</nav>
<div class="content">
<img src="http://placehold.it/640x360">
</div>
<div class="sidebar">
<div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro repudiandae, laboriosam dolorum mollitia fugit autem officiis explicabo minima! Maxime ea a unde alias laboriosam vel pariatur delectus. A, quas ratione?</div>
<div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Neque temporibus sunt, nesciunt et assumenda asperiores fuga aperiam nulla voluptas reprehenderit iusto molestias blanditiis corrupti, nobis ab id dolorum obcaecati ullam!</div>
</div>
</div>
Is there a way to craft this so the second row becomes a flexbox while keeping its height from expanding, so I could collapse the sidebar without having to re-layout a whole grid? (If there's a more clever way to get the img scaling I'm attempting, I'm open to that, too.)

Simply update the template to grid-template-columns: 1fr auto; and make the width of sidebar to be equal to 150px;
html,
body {
margin: 0;
}
.wrapper {
height: 100vh;
display: grid;
grid-template-columns: 1fr auto;
grid-template-rows: auto 1fr;
}
nav {
height: 50px;
grid-row: 1;
grid-column: 1 / span 2;
background-color: darkseagreen;
}
.content {
background-color: salmon;
position: relative;
}
img {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
object-fit: contain;
}
.sidebar {
overflow-y: scroll;
background-color: cornflowerblue;
width:150px;
}
<div class="wrapper">
<nav>Navbar should stay fixed</nav>
<div class="content">
<img src="http://placehold.it/640x360">
</div>
<div class="sidebar" style="display:none;">
<div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro repudiandae, laboriosam dolorum mollitia fugit autem officiis explicabo minima! Maxime ea a unde alias laboriosam vel pariatur delectus. A, quas ratione?</div>
<div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Neque temporibus sunt, nesciunt et assumenda asperiores fuga aperiam nulla voluptas reprehenderit iusto molestias blanditiis corrupti, nobis ab id dolorum obcaecati ullam!</div>
</div>
</div>

Related

how to show equal height of column using flex box

could you please tell me how to show equal height of column using flex-box.I tried like this
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.grid {
display: flex;
flex-wrap: wrap;
}
.card {
background-color: #eee;
padding: 20px;
}
.grid-item {
width: calc(50vw - 0px);
}
here is my code
https://codesandbox.io/s/prod-sea-ng305?file=/index.html:255-550
currently it look like this
To maintain the equal height of the div we have to use align-items: stretch property. That will maintain the height of the elements. Please find the code below.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.grid {
display: flex;
flex-wrap: wrap;
align-items: stretch;
}
.grid-item {
display: flex;
width: calc(50vw - 0px);
margin: 0 0 1px 0;
}
.card {
width: 100%;
background-color: #eee;
padding: 20px;
}
<div class="grid">
<div class="grid-item">
<div class="card">A very short text.</div>
</div>
<div class="grid-item">
<div class="card">
Debitis nam, porro officia dolorum cupiditate magnam perspiciatis quis
corrupti cumque, est perferendis provident vel accusamus ullam cum
similique. Quasi, quidem beatae. Debitis nam, porro officia dolorum
cupiditate magnam perspiciatis quis corrupti cumque, est perferendis
provident vel accusamus ullam cum similique. Quasi, quidem beatae.
</div>
</div>
<div class="grid-item">
<div class="card">
Officia autem sunt obcaecati voluptas sit, architecto cumque quaerat
aperiam fuga eveniet necessitatibus aliquid eum beatae, mollitia saepe
ab ut!
</div>
</div>
</div>
Here's the answer using flexbox as requested in the post. Though grid is likely an easier answer in terms of making a grid, and as such I included it at the end of the post.
align-items: stretch makes the elements change size on their cross axis (height when flex is set to row, and width when set to column) to stretch to fit. This makes the elements in the flexbox stretch to the same height as the largest element in the row.
Then by setting .card to have a height of 100%, the card will now take up that full height, though setting the .grid-item to use flex instead is also perfectly valid.
CSS Tricks Flex is a good resource for what flexbox can do.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
/* Makes the scrollbar not take up space so the demo shows on the small runner */
overflow-y: overlay;
}
.grid {
display: flex;
flex-wrap: wrap;
/* Makes the items cross axis of the flexbox stretch to the full size
of the cross axis
*/
align-items: stretch;
}
.card {
background-color: #eee;
padding: 20px;
/* Make the card take the height of it's containing item */
height: 100%;
}
.grid-item {
/* Makes the grid item take up half the width of the page */
width: calc(50vw - 0px);
}
#supports not (overflow: overlay) {
/* Backup to make sure the demo looks good on small runner on all devices
since overlay isn't supported on everything
*/
.grid-item {
width: calc(50vw - 8px);
}
}
<div class="grid">
<div class="grid-item">
<div class="card">
hello
</div>
</div>
<div class="grid-item">
<div class="card">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Error molestiae reiciendis voluptate cum fugiat nisi exercitationem quos ipsum iusto dolore. Quasi expedita accusantium at odio repellat explicabo corrupti veniam hic?
</div>
</div>
<div class="grid-item">
<div class="card">
third locthiLorem, ipsum dolor sit amet consectetur adipisicing elit. Error molestiae reiciendis voluptate cum fugiat nisi exercitationem quos ipsum iusto dolore. Quasi expedita accusantium at odio repellat explicabo corrupti veniam hic?
</div>
</div>
</div>
Here's the same but in a grid. It's simpler and uses fewer properties to get the same result.
This is all the CSS Grid related properties set:
.grid {
/* Make the grid use css grid */
display: grid;
/* Make 2 columns, each one fraction of the available width */
grid-template-columns: 1fr 1fr;
}
Though again, we need to set some height for the card because while the grid-item stretches height to fit, the card doesn't.
CSS Tricks Grid is a good resource for CSS Grid.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.grid {
display: grid;
/* Make 2 columns, each one fraction of the available width */
grid-template-columns: 1fr 1fr;
}
.card {
background-color: #eee;
padding: 20px;
/* Make the card take the height of it's containing item */
height: 100%;
}
<div class="grid">
<div class="grid-item">
<div class="card">
hello
</div>
</div>
<div class="grid-item">
<div class="card">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Error molestiae reiciendis voluptate cum fugiat nisi exercitationem quos ipsum iusto dolore. Quasi expedita accusantium at odio repellat explicabo corrupti veniam hic?
</div>
</div>
<div class="grid-item">
<div class="card">
third locthiLorem, ipsum dolor sit amet consectetur adipisicing elit. Error molestiae reiciendis voluptate cum fugiat nisi exercitationem quos ipsum iusto dolore. Quasi expedita accusantium at odio repellat explicabo corrupti veniam hic?
</div>
</div>
</div>

Exclude some part from background blend mode

I try to achieve effect similar to Photoshop multiply via code on my project. At the same time i try to exclude some elements that are in child div to be affected by it (like text layers) - and i hit in the wall. Tried already adding additional div's setting different z-index's or go with absolute position.
Here you can find pen with example of the problem:
HTML
<div class="main">
<div class="inner">
<h1>Some header</h1>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Quia eligendi est eius unde autem dolore adipisci perspiciatis laboriosam reiciendis placeat! Eveniet, quam? Vitae sit saepe quam delectus fugiat, dolores necessitatibus.</p>
</div>
</div>
CSS
.inner {
text-align: center;
padding: 50px 0;
background: #0079ff;
mix-blend-mode: multiply;
backface-visibility: hidden;
color: white;
}
.main {
background-repeat: no-repeat;
background-image: url('https://preview.ibb.co/fMY2f9/Bg1.jpg');
background-size: cover;
}
Summary: Child element's of 'child div' are affected by multiply. Is there a way to prevent that?
Screenshots:
Use pseudo element for the background to avoid this:
.inner {
text-align: center;
padding: 50px 0;
color: white;
}
.main {
background-repeat: no-repeat;
background-image: url('https://preview.ibb.co/fMY2f9/Bg1.jpg');
background-size: cover;
position: relative;
z-index: 0;
}
.main::before {
content: "";
position: absolute;
z-index: -1;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #0079ff;
mix-blend-mode: multiply;
}
<div class="main">
<div class="inner">
<h1>Some header</h1>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Quia eligendi est eius unde autem dolore adipisci perspiciatis laboriosam reiciendis placeat! Eveniet, quam? Vitae sit saepe quam delectus fugiat, dolores necessitatibus.</p>
</div>
</div>

Create a row of flexbox items with a max height defined by one child [duplicate]

This question already has answers here:
One flex/grid item sets the size limit for siblings
(6 answers)
Closed 6 years ago.
I'm trying to create a flexbox layout that does something I thought would be a little easier, but I'm having trouble finding the right way to do it.
I want to have a row of items with dynamic height that allows one child to grow as tall as need be, but limits the height of the other item so that content is cut off.
I want to use flexbox, so browser issues associated with that are not an issue, but I would like to avoid any use of JavaScript in the solution.
Any ideas? This might be a trivial problem, but I'm having trouble finding anything with the search terms I've been using. Thanks!
Here's a CodePen demo in case you'd like to modify it for use in your answer.
This is my reference flexbox layout:
.row {
display: flex;
}
.info {
flex: 0 0 200px;
}
.description {
flex: 1 1 auto;
}
<div class="row">
<div class="info">This should grow dynamically</div>
<div class="description">This should be limited in height by the .info div</div>
</div>
Flexbox can't do that natively but it is possible.
You will need an inner element inside the second child which is positioned absolutely.
Here the extra content is/can be hidden with overflow:hidden...or revealed by adding overflow:auto.
.wrapper {
display: flex;
width: 80%;
margin: 1em auto;
border: 2px solid red;
}
.child {
flex: 1;
border: 2px solid green;
}
.child:nth-child(2) {
position: relative;
overflow: auto;
/*overflow: hidden; */ /* removed for demo purposes */
}
.inner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
<div class="wrapper">
<div class="child">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Debitis tenetur, laboriosam! Ab facilis, officia id delectus eaque expedita quia, incidunt eligendi aut, minus temporibus tenetur.</div>
<div class="child">
<div class="inner">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quae molestiae, libero inventore nobis et veritatis, laborum vitae, vel eaque omnis ad adipisci quia velit blanditiis qui. Cum voluptas quisquam itaque possimus accusamus repellendus quia iure
asperiores. Unde, rerum nihil maiores nisi, iusto voluptate id cumque incidunt, perspiciatis facilis perferendis explicabo.
</div>
</div>
</div>

How to control number of items per row using media queries in Flexbox?

So imagine I have the following Markup
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
And the following styles (SASS)
#mixin max-width($width) {
#media screen and (max-width: $width) {
#content;
}
}
.container {
display: flex;
#include max-width(992px) {
number: 4; //Hypothetical property that is supposed to control number per row
}
#include max-width(640px) {
number: 2; //Hypothetical property that is supposed to control number per row
}
}
.item {
background-color: tomato;
padding: 20px;
margin-right: 20px;
flex: 1;
}
Is there a real Flexbox CSS alternative to my hypothetical number property that can control how many items to show per row ?
The float-like grid was handy because you could fit unlimited .items per one .row because of the width. But with flexbox I have to use workarounds like numerous .row classes to control the layout and number of items at different width. I've been lucky so far, but there are certain type of layout which will fail with such an approach.
Codepen link to demonstrate
I had to get rid of the margin around the blocks, because percentage widths are difficult to cleanly apply to elements with margins, but you can see the changes at http://codepen.io/anon/pen/jPeLYb?editors=110 :
#mixin max-width($width) {
#media screen and (max-width: $width) {
#content;
}
}
.container {
position: relative;
display: flex;
flex-flow: row wrap;
}
.item {
background-color: tomato;
box-sizing: border-box;
padding: 20px;
outline: 2px solid blue;
flex: 1;
}
#include max-width(992px) {
.item {
flex-basis: 25%;
background-color: red;
}
}
#include max-width(640px) {
.item {
flex-basis: 50%;
background-color: green;
}
}
The important parts here are:
flex-flow: row wrap which allows the flexbox to appear on multiple rows (the default is nowrap)
flex-basis which is the equivalent of width in this case
position: relative which makes the widths relative to the container, rather than the body (this would screw up the rounding)
I have found a better solution for restricting the number of columns in a row in different devices without using media queries:
HTML:
<div class="flex-container">
<div class="item">
<h3>ONE</h3>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Cumque maxime odit ipsam, fugit pariatur quis eos
maiores nostrum? Alias tempora voluptate veritatis omnis quae corporis vero excepturi in rem ipsam.
</div>
<div class="item">
<h3>TWO</h3>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Cumque maxime odit ipsam, fugit pariatur quis eos
maiores nostrum? Alias tempora voluptate veritatis omnis quae corporis vero excepturi in rem ipsam.
</div>
<div class="item">
<h3>THREE</h3>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Cumque maxime odit ipsam, fugit pariatur quis eos
maiores nostrum? Alias tempora voluptate veritatis omnis quae corporis vero excepturi in rem ipsam.
</div>
<div class="item">
<h3>FOUR</h3>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Cumque maxime odit ipsam, fugit pariatur quis eos
maiores nostrum? Alias tempora voluptate veritatis omnis quae corporis vero excepturi in rem ipsam.
</div>
</div>
CSS:
.flex-container {
display: flex;
flex-wrap: wrap;
}
.item {
box-sizing: border-box;
flex: 1 0 250px;
margin: 1rem;
padding: 1rem;
border: 1px solid #000;
border-radius: 5px;
}
Codepen link: https://codepen.io/bala285/pen/YzqpLod
Source: https://www.fourkitchens.com/blog/article/responsive-multi-column-lists-flexbox/

Fixed position relative to parent element [duplicate]

This question already has answers here:
Fixed position but relative to container
(31 answers)
Closed 4 years ago.
I am relatively new to CSS. I have run into a problem where I am trying to fix an element next to its parent element. I am able to do so with the following code:
Parent element:
#search_results{
position:relative;
}
Child element:
.total {
position: fixed;
top:10px;
width:250px;
left: 75%;
/*overflow: hidden;*/
margin-left: -125px;
}
This works fine until the browser window is resized. When that occurs, the fixed element overlaps its parent element. You can see my problem here:
Twittiment
I am trying to fix the child element to the top of the page and the right-hand side of the parent element. Any ideas?
Edit:
You can use position: sticky; which can be relative to the parent element.
body > div {
height: 300px;
background-color: #ddd;
overflow: auto;
margin-top: 70px;
}
div > div {
height: 1000px;
position: relative;
}
span {
display: block;
height: 20px;
background-color: tomato;
position: sticky;
top: 0;
}
<div>
<div>
<span>This is a relatively sticky header</span>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus voluptas pariatur ullam, dolores veritatis vero possimus nisi corrupti, provident aspernatur harum ab aliquam expedita assumenda, blanditiis aliquid id consequuntur distinctio.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus voluptas pariatur ullam, dolores veritatis vero possimus nisi corrupti, provident aspernatur harum ab aliquam expedita assumenda, blanditiis aliquid id consequuntur distinctio.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus voluptas pariatur ullam, dolores veritatis vero possimus nisi corrupti, provident aspernatur harum ab aliquam expedita assumenda, blanditiis aliquid id consequuntur distinctio.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus voluptas pariatur ullam, dolores veritatis vero possimus nisi corrupti, provident aspernatur harum ab aliquam expedita assumenda, blanditiis aliquid id consequuntur distinctio.</p>
</div>
</div>
Old Answer:
As per CSS Spec, the element positioned fixed is fixed to the viewport and not the containing element.
So the short answer is NO, you cannot have a fixed position element relative to it's parent element. You can use position: absolute; instead and tweak the top left right bottom parameters on the run using jQuery/JS.
Of course you can, just need an extra div!
<div class="fixed-wrapper">
<div class="close-wrapper">
<div class="close"></div>
</div>
</div>
body
background: gray
height: 8000px
.fixed-wrapper
position: fixed
top: 20px
left: 0
right: 0
.close-wrapper
max-width: 1200px
position: relative
.close
background: #fff
width: 30px
height: 30px
position: absolute
right: 0
border: 1px solid #515151
&:before,&:after
width: 25px
height: 1px
background: #515151
content: ''
position: absolute
top: 50%
left: 50%
display: block
#include transform(translate(-50%, -50%) rotate(45deg))
&:after
transform: translate(-50%, -50%) rotate(-45deg)
See this fiddle I made for you :-)
http://codepen.io/marinagallardo/pen/mJyqaN
The best way to achieve this is to give parent element a transform css.
eg:
.relative{
transform: translateX(0); // this will act like relative parent
}
.fixed{
position: fixed;
left:0;
top:0;
width:100%; // width will be relative to the width of .relative
}
What you want to use is position:absolute . This places the child element according to it's parent element.
Some readings here : http://www.w3schools.com/cssref/pr_class_position.asp

Resources