I am looking at having a header to a horizontal scrollable section that would have a date counter along the top, spanning the length of a year. Each date is represented by a single div. Weekends have a background color that is different than the week days. I am not using any graphics library, just straight HTML, CSS and JS. It is preferable that I do not need to change this.
My goal is to make it so that the weekend background color will extend down the main body of the panel without disrupting the layout and elements present there. The end result would look something like this:
Things I thought could potentially work:
Extend the background color of the weekend cells so that they continue vertically down the height of the main panel. This requires that background colors of cells can extend beyond the bounds of an element
Have the panel show different background colors at certain intervals. This would require the ability to alternate the background color of the SAME div multiple times
I am definitely open to any other ideas if I am simply unware of a better way to do things.
Optimization is a key concern, as I am expecting to have a couple of hundred rows of data (in a vertically scrollable div) as well as 300+ columns (in a horizontally scrollable div). I have run a test to determine if it was still responsive enough with a div per cell. The answer was most definitely not: it took seconds to load, it was laggy with the scrolling and overall just not nice to use. Not particularly surprising at 60,000 elements.
I have tried doing the following:
Doing a transform and pseduo selector on the weekend elements to extend the background (have had trouble with the :after element also extending the size of the current element). I've also had a problem trying to get the :after selector to apply down rather than to the right, even after trying some basic transforms
Making the entire thing discrete and adding divs for every representable day of a row. This was awful and unfortunately unusable at the scale I am expecting, but technically has the desired appearance
Sample code that can used to get a similar situation to my current environment:
#mainPanel {
overflow-x: scroll;
display: flex;
height: 100vh;
flex-direction: column;
}
#header {
height: 25px;
box-sizing: border-box;
display: flex;
flex-direction: row;
width: 100%;
}
.headCell {
height: 100%;
border: 1px #cccccc solid;
border-left: none;
box-sizing: border-box;
min-width: 25px;
display: flex;
align-items: center;
justify-content: center;
}
.weekend {
background-color: #efefef;
}
<div id="mainPanel">
<div id="header">
<div class="headCell">1</div>
<div class="headCell">2</div>
<div class="headCell">3</div>
<div class="headCell">4</div>
<div class="headCell">5</div>
<div class="headCell weekend">6</div>
<div class="headCell weekend">7</div>
<div class="headCell">8</div>
<div class="headCell">9</div>
<div class="headCell">10</div>
<div class="headCell">11</div>
<div class="headCell">12</div>
<div class="headCell weekend">13</div>
<div class="headCell weekend">14</div>
<div class="headCell">15</div>
<div class="headCell">16</div>
<div class="headCell">17</div>
<div class="headCell">18</div>
<div class="headCell">19</div>
<div class="headCell weekend">20</div>
</div>
<div id="panelBody">
Here is some text that will appear in the main div. I am hoping to see this not moved around and that the grey weekend lines will appear underneath the text.
</div>
</div>
Any help with concepts that could assist with this would be much appreciated, and any references to reading materials would be icing on the cake. Thanks a tonne in advance.
You can manipulate the .weekend::after pseudo element by adding this code:
.weekend::after{
content:'';
position:absolute;
height:100%;
width:25px;
top:1em;
z-index:-1;
background-color: #efefef;
}
Here is the full working code:
#mainPanel {
overflow-x: scroll;
display: flex;
height: 100vh;
flex-direction: column;
}
#header {
height: 25px;
box-sizing: border-box;
display: flex;
flex-direction: row;
width: 100%;
}
.headCell {
height: 100%;
border: 1px #cccccc solid;
border-left: none;
box-sizing: border-box;
min-width: 25px;
display: flex;
align-items: center;
justify-content: center;
}
.weekend {
background-color: #efefef;
}
.weekend::after{
content:'';
position:absolute;
height:100%;
width:25px;
top:1em;
z-index:-1;
background-color: #efefef;
}
<div id="mainPanel">
<div id="header">
<div class="headCell">1</div>
<div class="headCell">2</div>
<div class="headCell">3</div>
<div class="headCell">4</div>
<div class="headCell">5</div>
<div class="headCell weekend">6</div>
<div class="headCell weekend">7</div>
<div class="headCell">8</div>
<div class="headCell">9</div>
<div class="headCell">10</div>
<div class="headCell">11</div>
<div class="headCell">12</div>
<div class="headCell weekend">13</div>
<div class="headCell weekend">14</div>
<div class="headCell">15</div>
<div class="headCell">16</div>
<div class="headCell">17</div>
<div class="headCell">18</div>
<div class="headCell">19</div>
<div class="headCell weekend">20</div>
</div>
<div id="panelBody">
Here is some text that will appear in the main div. I am hoping to see this not moved around and that the grey weekend lines will appear underneath the text.
</div>
</div>
You can add an :after and set a width of 0 with a margin-left equal to the width of the cell (16px in this case.
This can be seen i the following:
#mainPanel {
overflow-x: scroll;
display: flex;
height: 100vh;
flex-direction: column;
}
#header {
height: 25px;
box-sizing: border-box;
display: flex;
flex-direction: row;
width: 100%;
}
.headCell {
height: 100%;
border: 1px #cccccc solid;
border-left: none;
box-sizing: border-box;
min-width: 25px;
display: flex;
align-items: center;
justify-content: center;
}
.weekend {
background-color: #efefef;
}
.weekend:after {
background-color: #efefef;
width: 20px;
height: 100vh; /* Adjust to suit */;
content: "";
display: inline-block;
margin-left: -16px;
z-index: -1;
}
<div id="mainPanel">
<div id="header">
<div class="headCell">1</div>
<div class="headCell">2</div>
<div class="headCell">3</div>
<div class="headCell">4</div>
<div class="headCell">5</div>
<div class="headCell weekend">6</div>
<div class="headCell weekend">7</div>
<div class="headCell">8</div>
<div class="headCell">9</div>
<div class="headCell">10</div>
<div class="headCell">11</div>
<div class="headCell">12</div>
<div class="headCell weekend">13</div>
<div class="headCell weekend">14</div>
<div class="headCell">15</div>
<div class="headCell">16</div>
<div class="headCell">17</div>
<div class="headCell">18</div>
<div class="headCell">19</div>
<div class="headCell weekend">20</div>
</div>
<div id="panelBody">
Here is some text that will appear in the main div. I am hoping to see this not moved around and that the grey weekend lines will appear underneath the text.
</div>
</div>
Related
Here is a codepen.
Here is code:
HTML
<div class="body">
<div class="page">
<div class="regular-flow">
</div>
<div class="regular-flow">
</div>
<div class="regular-flow">
</div>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
<div class="item">13</div>
<div class="item">14</div>
<div class="item">15</div>
<div class="item">16</div>
</div>
<div class="regular-flow">
</div>
<div class="regular-flow">
</div>
</div>
</div>
CSS
.body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: grey;
}
.page {
height: 100vh;
width: 100%;
background-color: lightgrey;
overflow: hidden;
}
.regular-flow {
height: 20px;
background-color: limegreen;
margin: 10px 24px;
}
.container {
width: 100%;
height: 25%;
padding-left: 24px;
padding-right: 24px;
background-color: orangered;
display: flex;
gap: 16px;
overflow-x: scroll;
-ms-overflow-style: none;
scrollbar-width: none;
}
.container::-webkit-scrollbar {
display: none;
}
.item {
height: 100%;
width: 121px;
color: yellow;
background-color: blue;
flex-shrink: 0;
}
We have several "regular flow" items (green) that keep their own margin consistently down the page (grey). However, I'd like to have a horizontal scrolling div (blue and orangered) that disrespects these boundaries, allowing items to seemingly pass from "edge" to "edge" of the screen. My thought was to overflowX: 'scroll' a 100% width div and put padding on the left and right equal to the margin being set by the other items. This way, on the "edges" of the scrollable content, it appears to still respect the margin set by the other regularly flowing items. However, no matter what I try or how many items you put into this container, it will always scroll right only to the right edge of the last item. It will not show the last bit of right padding.
Things to keep in mind about the codepen
You have to have enough items for it to need to scroll horizontally, obviously.
I am hiding the scrollbar, so hover over the blue/orange container and shift+scrollwheel to move the items. I know this isn't great UX.
Most Basic Question
Why can you not scroll right far enough such that the padding-right (orangered) is visible?
Update
I was able to come up with a workaround for this issue, and that is to go into the parent component (in my codepen, this would be .container and remove the padding-right and padding-left at that level, but then add:
.container & .div:first-child {
padding-left: 24,
}
.container & .div:last-child {
padding-right: 24,
}
This seems to accomplish the same goals, but only if you do NOT have any background color to the .item. For my purposes, this works. I only added a background color here for visualizing the issue. I would still be curious if anyone can tell me what the problem above was, so I will keep this question up and not edit the codepen. Thanks!
I'd like to overlay two icons over another div and also align them to the right.
The relevant code at the moment can be summarized as
<div class="container">
<div class="icon">icon1</div>
<div class="icon">icon2</div>
</div>
.container {
position: relative
}
.icon {
position: absolute
right: 0px
}
As it stands, the icons align to the right over the div, but also overlap over one another. How would I fix this?
If I understand you correctly, this might be the result you're looking for ?
.container {
position: relative;
width: 180px;
height: 180px;
border: 1px dashed red;
display: flex;
align-items: flex-start;
justify-content: flex-end;
}
<div class="container">
<div class="icon">icon1</div>
<div class="icon">icon2</div>
</div>
In the following html I want the txt-box div to be centered in the container, overlay the image, and expand to fill the container. It should have a margin of equal width on all sides allowing part of the image to show like a thick border.
The html shown is passable for what I want except the vertical vs. horizontal margins are always slightly different as the browser window is resized.
I feel like what I have here is a hack and that I am using flex-grow incorrectly. I understand flex-grow works to allow the txt-box div to expand since it is the only element with a grow value. If I can get that resolved I should be able to simply set a margin on txt-box and it should work.
What am I not understanding about flex-grow?
.container {
display: flex;
align-items: center;
justify-content: center;
border: solid 2px red;
position: relative;
}
.container img {
width: 100%;
flex-grow: 0;
flex-shrink: 0;
}
.txt-box {
background-color: white;
display: flex;
padding: 5px;
border: solid 2px blue;
flex-grow: 1;
position: absolute;
width: 90%;
height: 80%;
}
<div class="container">
<img src="blocks.png" />
<div class="txt-box">
hello world
</div>
</div>
Thanks to Michael Benjamin for putting me on the path to enlightenment. I finally got it figured out. My original question was actually a portion of what I was trying to accomplish. The answers are to use background-image:url('...') and make sure the table and row elements are display:flex.
JSFiddle
<html>
<head>
<style>
.flex-table {
flex-flow:column;
}
.flex-row {
flex-flow:row;
}
.container {
align-items: center;
justify-content: center;
padding: 20px;
border: solid 2px red;
background-image:url('https://i.imgur.com/BF3ty6o.jpg');
background-size:cover;
background-repeat:no-repeat;
max-width:500px;
}
.txt-box {
justify-self:stretch;
align-self:stretch;
border: solid 2px blue;
background-color: rgba(192,192,192,0.5);
}
body, .flex-table, .flex-row, .container, .txt-box {
display:flex;
flex-grow:1;
}
#media (max-width: 768px) {
.flex-row {
flex-flow:column;
}
}
</style>
</head>
<body>
<div class="flex-table">
<div class="flex-row">
<div class="container">
<div class="txt-box">
hello world 1
</div>
</div>
<div class="container">
<div class="txt-box">
hello world 2
</div>
</div>
<div class="container">
<div class="txt-box">
hello world 3
</div>
</div>
</div>
<div class="flex-row">
<div class="container">
<div class="txt-box">
hello world 4
</div>
</div>
<div class="container">
<div class="txt-box">
hello world 5
</div>
</div>
<div class="container">
<div class="txt-box">
hello world 6
</div>
</div>
</div>
</div>
</body>
</html>
What am I not understanding about flex-grow?
Flex properties don't work on absolutely positioned children of a flex container.
ยง 4.1. Absolutely-Positioned Flex
Children
As it is out-of-flow, an absolutely-positioned child of a flex
container does not participate in flex layout.
Therefore, flex-grow: 1 on txt-box is not doing anything. It's just being ignored.
Considering that you want the image simply laying in the background, while the text box has more requirements, I would suggest absolutely positioning the image and leaving the text box in the normal flow.
Then give the text box full width and height, with equal padding on the primary container to keep uniform "margins" across screen sizes.
Here's a demo, with a few extra features to help illustrate the concepts involved.
body {
height: 100vh;
display: flex;
margin: 0;
padding: 10px;
}
.container {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
position: relative;
border: solid 2px red;
}
img {
position: absolute;
height: 100%;
width: 100%;
object-fit: contain; /* also try 'cover' for demo */
}
.txt-box {
z-index: 1;
width: 100%;
height: 100%;
border: solid 2px blue;
background-color: rgba(192,192,192,0.5);
}
* {
box-sizing: border-box;
}
<div class="container">
<img src="http://i.imgur.com/60PVLis.png">
<div class="txt-box">hello world</div>
</div>
jsFiddle demo
I am trying to create tab module such as this:
https://codepen.io/oknoblich/pen/tfjFl
However I am having difficulty since I can not change the HTML layout:
<div class="container">
<div class="tab-header">Tab1</div>
<div class="tab-content teal">Content1</div>
</div>
<div class="container current">
<div class="tab-header">Tab2</div>
<div class="tab-content teal">Content2</div>
</div>
The problems are that absolute positioning removes the content from the document flow, while other methods prevents the content from being the full width of the page.
I created two codepen's that illustrates the difficulties:
https://codepen.io/dwigt/pen/pOQpLd (absolute positioning removes content from document flow)
https://codepen.io/dwigt/pen/YOREOJ (flexbox layout does not take up full page-width)
Is there anyway I can replicate the tab functionality using this HTML layout and no javascript?
You can use display: contents (which is unfortunately not too well supported) combined with flexbox layout with wrap, set on the .wrapper element. This way, tab-headers and tab-contents will be treated equally, as if they were at the same level with one another - the .container elements are "transparent" to the layout engine. As a result, they will all be laid out with flexbox logic applied. Finally, to have the three tab headers display first, we set the order of the tab contents to some high value (here 100), and since we have flex wrap enabled, the content is then pushed downwards to a new line, below the headers. See example below:
.wrapper {
max-width: 300px;
display: flex;
flex-wrap: wrap;
height: 100%;
}
.container {
height: 50px;
display: contents;
}
.container .tab-header {
width: 100px;
max-width: 100%;
max-height: 100%;
flex: 1 0 33.33%;
}
.container .tab-content {
display: none;
height: 200px;
order: 100;
}
.container.current .tab-content {
display: block;
width: 300px;
left: 0;
}
.footer {
height: 500px;
width: 300px;
display: block;
}
.red {
background: red;
}
.teal {
background: teal;
}
<div class="wrapper">
<div class="container">
<div class="tab-header">Tab1</div>
<div class="tab-content teal">Content1</div>
</div>
<div class="container current">
<div class="tab-header">Tab2</div>
<div class="tab-content teal">Content2</div>
</div>
<div class="container">
<div class="tab-header">Tab3</div>
<div class="tab-content teal">Content3</div>
</div>
</div>
<div class="footer red">Footer Text</div>
This isn't quite perfect because the first tab is a bit wider, but give this a shot and see if this doesn't get your closer to your goal. It allows your tabs to be 100% and also allows you to add more tabs that space evenly from edge to edge of your container.
Let me know how it works out :D
Add display: table-cell and width: 100% to your css selector label
label {
display: table-cell;
width: 100%;
margin: 0 0 -1px;
padding: 15px 25px;
font-weight: 600;
text-align: center;
color: #bbb;
border: 1px solid transparent;
}
I have the following layout (simplified version). .account is the flex-container and .card-two holds the actual table. When there is a lot of content, everything works fine, but when .card-two doesn't have enough content (when showing error messages), it does not fill the height of its parent .content. the cards have a background color set, so the entire effect looks quite ugly.
How do I make the card behave and stretch to fill its container? I tried setting height on .account, setting flex-basis:1 0 0, but it doesn't work. setting height:100% to .card-two just makes it massively overflow its parent. Note: I do not have a lot of control on the HTML.
HTML code:
<div class="container">
<div class="account">
<div class="sidebar">This is a sidebar aka the first column</div>
<div class="content">
<div class="card-one">this is card number one. full width of the parent</div>
<div class="card-two">this card should have a lot of content. but sometimes it doesn't.</div>
</div>
</div>
</div>
CSS (without the changes I have tried):
.container{
// just a generic container.
width:1140px; margin:auto;
}
.account{
display: flex;
}
.sidebar{
width: 25%;
}
.content{
width: 75%;
}
here's a codepen (with some comments as to what I have tried): https://codepen.io/samia92/full/MVJqwQ
any help is much appreciated.
You need to add flex to .content then only card-two can have flexbox properties.
.container {
width: 600px;
margin: auto;
box-sizing: border-box;
}
.account {
display: flex;
height: 400px;
}
.card {
background: #ddd;
box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.5);
padding: 15px;
}
.sidebar {
width: 25%;
margin-right: 10px;
}
.content {
width: 75%;
display: flex; /*Addded*/
flex-direction: column; /*Addded*/
}
.card-one {
margin-bottom: 20px;
}
.card-two {
flex: 1; /*Addded*/
}
<div class="container">
<div class="account">
<div class="sidebar card">
This is a sidebar aka the first column
</div>
<div class="content">
<div class="card-one card">
<p>this is card number one. full width of the parent</p></div>
<div class="card-two card"><p>this card should have a lot of content. but sometimes it doesn't.</p>
<p>I want it to expand to it's parent, which has appropriate height</p>
<p>There You go.</p>
</div>
</div>
</div>
</div>