CSS Modal Scrolling - html

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

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 {}

Overflow-x stops working when I add overflow-y

.scrollable-items {
height: 100px;
overflow-x: unset;
overflow-y: auto;
width: 60px;
}
.cx-mainnav-hoverwrapper {
position: relative;
}
.cx-mainnav-hoverlabel {
display: inline;
position: absolute;
top: 0;
left: 50px;
margin-top: 10px;
opacity: 0;
pointer-events: none;
display: none;
}
.cx-mainnav:hover + .cx-mainnav-hoverlabel {
opacity: 1;
display: block;
}
<div class="scrollable-items">
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 1</div>
<div class="cx-mainnav-hoverlabel">Icon 1 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 2</div>
<div class="cx-mainnav-hoverlabel">Icon 2 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 3</div>
<div class="cx-mainnav-hoverlabel">Icon 3 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 4</div>
<div class="cx-mainnav-hoverlabel">Icon 4 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 5</div>
<div class="cx-mainnav-hoverlabel">Icon 5 Tooltip</div>
</div>
Basically, I have one vertical navigation bar
Before adding scrollbar-y, I used to see tooltip on hovering on element in left side of icon.
But, once I added overflow-y as auto, now I can't see tooltip on hover in left side of icon.
In this context, I want to add scrollbar on y axis, but I want to show tooltip as well in left side of icon when I hover over element. Currently, I am not able to achieve both things at same time.
You could unset the overflow-y on hover.
.scrollable-items {
min-height: 300px;
overflow-x: unset;
overflow-y: auto;
width: 50px;
}
.scrollable-items:hover {
overflow-y: unset;
}
.cx-mainnav-hoverwrapper {
position: relative;
}
.cx-mainnav-hoverlabel {
display: inline;
position: absolute;
top: 0;
left: 50px;
margin-top: 10px;
opacity: 0;
pointer-events: none;
}
.cx-mainnav:hover+.cx-mainnav-hoverlabel {
opacity: 1;
}
<div class="scrollable-items">
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 1</div>
<div class="cx-mainnav-hoverlabel">Icon 1 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 2</div>
<div class="cx-mainnav-hoverlabel">Icon 2 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 3</div>
<div class="cx-mainnav-hoverlabel">Icon 3 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 4</div>
<div class="cx-mainnav-hoverlabel">Icon 4 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 5</div>
<div class="cx-mainnav-hoverlabel">Icon 5 Tooltip</div>
</div>
You'll have to decide whether that is good enough for your real life case (the scrollbar disappearing on hover for example).
.scrollable-items {
min-height: 100px;
overflow-x: unset;
overflow-y: auto;
width: 60px;
}
.cx-mainnav-hoverlabel {
display: inline;
position: absolute;
left: 50px;
opacity: 0;
pointer-events: none;
padding: 2px 3px;
border-radius: 3px;
}
.cx-mainnav:hover + .cx-mainnav-hoverlabel {
background-color: crimson;
color: white;
opacity: 1;
display: block;
}
<div class="scrollable-items">
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 1</div>
<div class="cx-mainnav-hoverlabel">Icon 1 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 2</div>
<div class="cx-mainnav-hoverlabel">Icon 2 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 3</div>
<div class="cx-mainnav-hoverlabel">Icon 3 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 4</div>
<div class="cx-mainnav-hoverlabel">Icon 4 Tooltip</div>
</div>
<div class="cx-mainnav-hoverwrapper">
<div class="cx-mainnav">Icon 5</div>
<div class="cx-mainnav-hoverlabel">Icon 5 Tooltip</div>
</div>
</div>
I hope this answers you question. (the comments section is always open)
.scrollable-items {
width: 100px;
height: 90px;
/* position: relative; */
overflow-y: auto;
/* to make it scrollable 'y' only */
overflow-x: hidden;
font-size: 1.5rem;
}
.cx-mainnav {
/*position: relative;*/
display: inline;
}
.cx-mainnav-hoverwrapper {
/* position: relative; */
position: absolute;
visibility: hidden;
}
.cx-mainnav-hoverlabel {
display: block;
position: relative;
font-size: 1.1rem;
}
.cx-mainnav:hover .cx-mainnav-hoverwrapper {
visibility: visible;
opacity: 1;
}
<div class="scrollable-items">
<div class="cx-mainnav">
<span>Icon 1</span>
<span class="cx-mainnav-hoverwrapper"><span class="cx-mainnav-hoverlabel">Icon 1 tooltip</span></span>
</div>
<div class="cx-mainnav">
<span>Icon 2</span>
<span class="cx-mainnav-hoverwrapper"><span class="cx-mainnav-hoverlabel">Icon 2 tooltip</span></span>
</div>
<div class="cx-mainnav">
<span>Icon 3</span>
<span class="cx-mainnav-hoverwrapper"><span class="cx-mainnav-hoverlabel">Icon 3 tooltip</span></span>
</div>
<div class="cx-mainnav">
<span>Icon 4</span>
<span class="cx-mainnav-hoverwrapper"><span class="cx-mainnav-hoverlabel">Icon 4 tooltip</span></span>
</div>
<div class="cx-mainnav">
<span>Icon 5</span>
<span class="cx-mainnav-hoverwrapper"><span class="cx-mainnav-hoverlabel">Icon 5 tooltip</span></span>
</div>
</div>
The reason you see tooltip 4 and 5 a little off positioned is because of real and pseudo positioning (that is because of scrolling).

CSS position: sticky not working inside a wrapper element

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?

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>

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>