CSS position: sticky not working inside a wrapper element - html

I'm trying CSS position: sticky property, it works in a simple parent and child structure. But, when I'm trying to implement it in a more complex parent and child HTML structure, it doesn't work as expected.
In example below, I want to make <div class="ribbon"> as sticky element with a parent div as sticky container named <div classs="element">, and its grandparent named <div class="viewport"> acts as the scrollable viewport. It should stick on the left: 0 whenever I scroll the viewport scrollbar, but it doesn't.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
white-space: nowrap;
}
html, body {
font-size: 14px;
}
div {
position: relative;
display: block;
}
.container {
display: inline-block;
}
.container > .viewport {
overflow: scroll;
}
.container > .viewport > .content {
padding: 1em;
}
.container > .viewport > .content > .element {
margin-bottom: 1em;
}
.ribbon {
position: -webkit-sticky;
position: sticky;
left: 0;
padding: .5em;
background-color: bisque;
}
.ribbon .item {
display: inline-block;
margin-right: .5em;
padding: .5em;
background-color: aqua;
}
.grid {
padding: .5em;
background-color: brown;
}
<div class="container" style="width: 40em">
<div class="viewport">
<div class="content">
<div class="element">
<div class="container ribbon" style="width: 50em">
<div class="viewport">
<div class="content">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
<div class="item">Item 4</div>
<div class="item">Item 5</div>
<div class="item">Item 6</div>
<div class="item">Item 7</div>
<div class="item">Item 8</div>
<div class="item">Item 9</div>
<div class="item">Item 10</div>
<div class="item">Item 11</div>
<div class="item">Item 12</div>
<div class="item">Item 13</div>
</div>
</div>
</div>
</div>
<div class="element">
<div class="grid">
<div class="content">
<h4>Grid content</h4>
<h4>Grid content</h4>
<h4>Grid content</h4>
<h4>Grid content</h4>
<h4>Grid content</h4>
<h4>Grid content</h4>
</div>
</div>
</div>
</div>
</div>
</div>
Is there anything wrong with this?

Related

Why isn't row-gap working on the left grid?

I have two separate one-column grids side by side. The html layout is the same for both grids but in css the grid on the left is not showing row-gap on the webpage.
html:
<div class="both-grids">
<div class="show-grid-container">
<div class="grid-item">show 1</div>
<div class="grid-item">show 2</div>
<div class="grid-item">show 3</div>
<div class="grid-item">show 4</div>
<div class="grid-item">show 5</div>
</div>
<div class="movie-grid-container">
<div class="grid-item">movie 1</div>
<div class="grid-item">movie 2</div>
<div class="grid-item">movie 3</div>
<div class="grid-item">movie 4</div>
<div class="grid-item">movie 5</div>
</div>
</div>
css:
.both-grids {
padding-left: 100px;
}
.show-grid-container, .movie-grid-container {
display: inline-grid;
grid-template-rows: 40px 200px 200px 200px 200px;
row-gap: 40px;
}
.movie-grid-container {
padding-left: 80px;
}
.show-grid-container, .movie-grid-container > div {
background-color: black;
padding-right: 80px;
padding-left: 80px;
}
You are missing > div on .show-grid-container in the last piece of CSS
.both-grids {
padding-left: 100px;
}
.show-grid-container, .movie-grid-container {
display: inline-grid;
grid-template-rows: 40px 200px 200px 200px 200px;
row-gap: 40px;
}
.movie-grid-container {
padding-left: 80px;
}
.show-grid-container >div, .movie-grid-container >div {
background-color: black;
padding-right: 80px;
padding-left: 80px;
color:white;
}
<div class="both-grids">
<div class="show-grid-container">
<div class="grid-item">show 1</div>
<div class="grid-item">show 2</div>
<div class="grid-item">show 3</div>
<div class="grid-item">show 4</div>
<div class="grid-item">show 5</div>
</div>
<div class="movie-grid-container">
<div class="grid-item">movie 1</div>
<div class="grid-item">movie 2</div>
<div class="grid-item">movie 3</div>
<div class="grid-item">movie 4</div>
<div class="grid-item">movie 5</div>
</div>
</div>
Use this in css
.show-grid-container >div, .movie-grid-container >div {}
instead of
yours -> .show-grid-container, .movie-grid-container > div {}

Trello alike CSS layout

I'm trying to accomplish a layout similar to Trello:
kanban is always fully visible.
lane shrinks to fit the cardList.
cardList overflows when it reaches the bottom of kanban
kanban overflows horizontally when lanes are out of sight.
I'm not sure how to overflow the cardList component. I know it currently doesn't work because of the height: 100% property within .cardList, but I'd like to not have to give it a fixed height.
Also, I can't seem to overflow the kanban horizontally when I add overflow-x: scroll to .kanban.
Here's also a codesandbox in case it's easier.
:root {
--padding-card: 4px;
}
.App {
font-family: sans-serif;
text-align: center;
}
.container {
height: 90vh;
}
.kanbanWrapper {
background: black;
height: 100%;
overflow: hidden;
}
.kanban {
display: inline-flex;
background: lightgrey;
border-radius: 4px;
padding: 1rem;
margin: 1rem;
}
.kanban .lane {
margin: 0 var(--padding-card);
}
.lane {
height: 100%;
display: flex;
flex-direction: column;
background: lightpink;
width: 200px;
overflow: auto;
}
.laneHeader {
font-weight: bold;
border: 1px solid black;
padding: 0.5rem 0;
}
.laneFooter {
font-weight: bold;
border: 1px solid green;
}
.cardList {
padding: 4px;
min-height: 150px;
display: flex;
flex-direction: column;
height: 100%;
overflow: auto;
border: 1px solid blue;
}
.cardList .card {
margin: var(--padding-card);
}
.card {
background: lightgreen;
border-radius: 4px;
padding: 1rem 2rem;
}
<div class="App container">
<div class="kanbanWrapper">
<div class="kanban">
<div class="lane">
<div class="laneHeader">To do</div>
<div class="cardList">
<div class="card">Card 1 Longer title...</div>
<div class="card">Card 2</div>
<div class="card">Card 3</div>
<div class="card">Card 4</div>
<div class="card">Card 5</div>
<div class="card">Card 6</div>
<div class="card">Card 7</div>
<div class="card">Card 8</div>
<div class="card">Card 9</div>
<div class="card">Card 10</div>
<div class="card">Card 11</div>
<div class="card">Card 12</div>
</div>
<div class="laneFooter">+ Add card</div>
</div>
<div class="lane">
<div class="laneHeader">Doing</div>
<div class="cardList">
<div class="card">Card 11</div>
<div class="card">Card 12</div>
<div class="card">Card 13</div>
<div class="card">Card 14</div>
<div class="card">Card 15</div>
<div class="card">Card 16</div>
<div class="card">Card 17</div>
</div>
<div class="laneFooter">+ Add card</div>
</div>
<div class="lane">
<div class="laneHeader">Done</div>
<div class="cardList">
<div class="card">Card 21</div>
<div class="card">Card 22</div>
</div>
<div class="laneFooter">+ Add card</div>
</div>
<div class="lane">
<div class="laneHeader">Quality</div>
<div class="cardList"></div>
<div class="laneFooter">+ Add card</div>
</div>
</div>
</div>
</div>

Keep flex items fixed while resizing window

I am working on a web app and I need help with css. I am a beginner at css so please bear with me.
I'm trying to style a fixed sidebar for an app. The sidebar occupies the full height of the browser window. The whole sidebar is a flex box and the flex children are nested flex boxes as well.
Presently, the flex children move along with the browser window while reducing the viewport height and so the menu links get pushed up (but the avatar and username element remain fixed?!).
I don't want this to happen. The menu items inside the parent container should get clipped (instead of moving along with the browser window) and the user can scroll down to view the remaining menu items (like the sidebar on the youtube website for example).
For easy reference, here is the imgur link of what is current result and what I actually want: https://imgur.com/a/VShsF6o
Also, the scroll bar seems to take up extra width while appearing. Is there any way to stop that behavior?
https://jsfiddle.net/qbw1aLyz/8/
html {
background-color: #141E30;
margin: 0;
padding: 0;
}
.sidebar {
display: flex;
flex-direction: column;
width: 300px;
top: 0;
bottom: 0;
position: fixed;
overflow: auto;
background: #0a0c0f;
color: #EAE9E9;
}
.sidebar__profile {
padding: 16px;
display: flex;
flex-direction: column;
align-items: center;
}
.sidebar__menuitem {
padding-bottom: 10px;
display: flex;
align-items: center;
flex-shrink: 0;
height: 30px;
}
.count {
margin-left: auto;
margin-right: 20px;
border-radius: 6px;
padding: 2px 5px;
background-color: #EAE9E9;
color: #0a0c0f;
}
<div class="sidebar">
<div class="sidebar__profile">
<img src="http://chittagongit.com//images/avatar-icon/avatar-icon-4.jpg" height=50px alt="image" class="sidebar__profile__avatar" />
<div class="sidebar__profile__name">User Name</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 1</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 2</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 3</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 4</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 5</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 6</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 7</div>
<div class="count">2</div>
</div>
</div>
Just wrap .sidebar__profile in another div so it can act as a block-element rather than a shrinking flex-element...
html {
background-color: #141E30;
margin: 0;
padding: 0;
}
.sidebar {
display: flex;
flex-direction: column;
width: 300px;
top: 0;
bottom: 0;
position: fixed;
overflow: auto;
background: #0a0c0f;
color: #EAE9E9;
}
.sidebar__profile {
padding: 16px;
display: flex;
flex-direction: column;
align-items: center;
}
.sidebar__menuitem {
padding-bottom: 10px;
display: flex;
align-items: center;
flex-shrink: 0;
height: 30px;
}
.count {
margin-left: auto;
margin-right: 20px;
border-radius: 6px;
padding: 2px 5px;
background-color: #EAE9E9;
color: #0a0c0f;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>title</title>
</head>
<body>
<div class="sidebar">
<div>
<div class="sidebar__profile">
<img src="http://chittagongit.com//images/avatar-icon/avatar-icon-4.jpg" height=50px alt="image" class="sidebar__profile__avatar" />
<div class="sidebar__profile__name">User Name</div>
</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 1</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 2</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 3</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 4</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 5</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 6</div>
<div class="count">2</div>
</div>
<div class="sidebar__menuitem">
<div>Menu Item 7</div>
<div class="count">2</div>
</div>
</div>
</body>
</html>
Try wrapping the menu items in their own container, giving that container a scrolling function, and disabling shrinking on the profile.
Add this to your code:
nav {
overflow: auto;
}
.sidebar__profile {
align-self: center;
flex-shrink: 0;
}
revised jsfiddle demo

Select specific divs with an nth selector?

I have 12 divs tied to the same class but with different IDs and I want to apply a margin to specific ones, is this possible with a nth selector?
I have a rough example below (I'm using a sprite sheet in my actual project, so all the ra IDs have a background position set along with a width and height).
.tra-ra-cont {
display: flex;
flex-flow: row wrap;
justify-content: center;
}
.tra-ra-box {
line-height: 210px;
text-align: center;
margin: 3px;
}
.tra-ra-box a {
height: 210px;
width: 270px;
display: block;
font-size: 18px;
text-decoration: none;
color: black;
}
#ra1,
#ra2,
#ra3,
#ra4,
#ra5,
#ra6,
#ra7,
#ra8,
#ra9,
#ra10,
#ra11,
#ra12 {
background-repeat: no-repeat;
background-color: lightblue;
width: 270px;
height: 210px;
}
<div class="tra-ra-cont">
<div class="tra-ra-box" id="ra1">Range 1</div>
<div class="tra-ra-box" id="ra2">Range 2</div>
<div class="tra-ra-box" id="ra3">Range 3</div>
<div class="tra-ra-box" id="ra4">Range 4</div>
<div class="tra-ra-box" id="ra5">Range 5</div>
<div class="tra-ra-box" id="ra6">Range 6</div>
<div class="tra-ra-box" id="ra7">Range 7</div>
<div class="tra-ra-box" id="ra8">Range 8</div>
<div class="tra-ra-box" id="ra9">Range 9</div>
<div class="tra-ra-box" id="ra10">Range 10</div>
<div class="tra-ra-box" id="ra11">Range 11</div>
<div class="tra-ra-box" id="ra12">Range 12</div>
</div>
I need to apply margins to these IDs: ra2, ra3, ra6, ra7, ra10 and ra11
You can use nth-child 4n+2 (ra2, ra6 and ra10) and 4n+3 (ra3, ra7 and ra11):
.tra-ra-cont {
display: flex;
flex-flow: row wrap;
justify-content: center;
}
.tra-ra-box {
line-height: 210px;
text-align: center;
margin: 3px;
}
.tra-ra-box a {
height: 210px;
width: 270px;
display: block;
font-size: 18px;
text-decoration: none;
color: black;
}
.tra-ra-box {
background-repeat: no-repeat;
background-color: lightblue;
width: 270px;
height: 210px;
}
.tra-ra-cont > div:nth-child(4n + 2),
.tra-ra-cont > div:nth-child(4n + 3) {
background-color:red;
}
<div class="tra-ra-cont">
<div class="tra-ra-box" id="ra1">Range 1</div>
<div class="tra-ra-box" id="ra2">Range 2</div>
<div class="tra-ra-box" id="ra3">Range 3</div>
<div class="tra-ra-box" id="ra4">Range 4</div>
<div class="tra-ra-box" id="ra5">Range 5</div>
<div class="tra-ra-box" id="ra6">Range 6</div>
<div class="tra-ra-box" id="ra7">Range 7</div>
<div class="tra-ra-box" id="ra8">Range 8</div>
<div class="tra-ra-box" id="ra9">Range 9</div>
<div class="tra-ra-box" id="ra10">Range 10</div>
<div class="tra-ra-box" id="ra11">Range 11</div>
<div class="tra-ra-box" id="ra12">Range 12</div>
</div>

CSS Modal Scrolling

Please see the following Plunk: https://plnkr.co/edit/se1lRiXuQ4JtvqQcEtOA
I'm trying to create a modal suitable for a mobile application. Without changing the ordering of the HTML I need the CSS to achieve the following:
Fix the Header at the top (always visible) when scrolling
Keep the Buttons fixed underneath the header (always visible)
Make the Item list scrollable
As the heights of the elements may vary I'd like to be able to do this generically. So that the heights are automatically calculated
I'm stumped, any ideas?
HTML
<div class="modal">
<div class="modal-title">
Header
</div>
<div class="modal-content">
<div class="button-group">
<div class="button selected">Button One</div>
<div class="button">Button Two</div>
</div>
<div class="list"></div>
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
<div class="item">Item 4</div>
<div class="item">Item 5</div>
<div class="item">Item 6</div>
<div class="item">Item 7</div>
<div class="item">Item 8</div>
<div class="item">Item 9</div>
<div class="item">Item 10</div>
<div class="item">Item 11</div>
<div class="item">Item 12</div>
<div class="item">Item 13</div>
<div class="item">Item 14</div>
<div class="item">Item 15</div>
<div class="item">Item 16</div>
<div class="item">Item 17</div>
<div class="item">Item 18</div>
<div class="item">Item 19</div>
<div class="item">Item 20</div>
<div class="item">Item 21</div>
<div class="item">Item 22</div>
<div class="item">Item 23</div>
<div class="item">Item 24</div>
<div class="item">Item 25</div>
<div class="item">Item 26</div>
<div class="item">Item 27</div>
<div class="item">Item 28</div>
<div class="item">Item 29</div>
<div class="item">Item 30</div>
<div class="item">Item 31</div>
<div class="item">Item 32</div>
<div class="item">Item 33</div>
<div class="item">Item 34</div>
<div class="item">Item 35</div>
<div class="item">Item 36</div>
<div class="item">Item 37</div>
<div class="item">Item 38</div>
<div class="item">Item 39</div>
<div class="item">Item 40</div>
</div>
</div>
CSS
body {
margin: 0;
}
.modal {
position: absolute;
height: 100%;
width: 100%;
background: #e9f0f6;
overflow: hidden;
}
.modal-title {
background: #FF5722;
height: 52px;
text-align: center;
color: white;
font-size: 1.40em;
line-height: 52px;
}
.modal-content {
height: auto;
}
.button-group {
display: flex;
}
.button.selected {
background: #03A9F4;
color: white;
}
.button {
flex: 1;
background: #2196F3;
color: white;
height: 26px;
text-align: center;
line-height: 26px;
cursor: pointer;
}
.list {
overflow-y: scroll;
height: 100%;
}
.item {
text-align: center;
font-size: 1.40em;
padding: 10px;
}
Add the following changes to your CSS:
1. First, make your title position: fixed;, and give it a width: 100%.
.modal-title {
position: fixed;
width: 100%;
}
2. Do the same with the title, and add a top: 52px; so it won't be behind your title.
.button-group {
top: 52px;
position: fixed;
width: 100%;
}
3. To make the list scrollable, remove the position: absolute; from your .modal class, then add some margin so your list isn't hidden behind your header and buttons.
.modal {
position: absolute; //<--- Remove this
}
.modal-content {
margin-top: 78px;
}
JSFiddle
As for the dynamic height issue, you cannot do that with CSS alone. Refer to this JavaScript solution if you'd like the buttons or title to change heights.
.modal-title{
position: fixed;
top: 0;
bottom: 0;
width: 100%;
}
.button-group{
position: fixed;
top: 52px;
width: 100%;
}
.modal{
overflow: auto;
}
now some items are hidden behind the header. Fix:
.modal-content {
margin-top: 78px;
}
EDIT: Oh Hunter was faster, sorry