I need to build a card with two scrolling areas. Initial idea was to use flexbox so I came up with this:
.card {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 50%;
min-width: 100px;
min-height: 0;
max-width: 80%;
max-height: 80%;
border: solid 1px black;
padding: 10px;
}
.photo {
background-color: silver;
margin-bottom: 10px;
aspect-ratio: 3;
}
.body {
display: flex;
}
.content {
flex: 1;
display: flex;
flex-direction: column;
margin-right: 10px;
}
.title {
background-color: silver;
margin-bottom: 10px;
}
.text {
flex: 1;
background-color: cyan;
min-height: 0;
overflow: auto;
}
.photos {
width: 100px;
min-height: 0;
overflow: auto;
}
.photos * ~ * {
margin-top: 10px;
}
.thumbnail {
background-color: lightgreen;
aspect-ratio: 3;
}
<div class="card">
<div class="photo">Photo</div>
<div class="body">
<div class="content">
<div class="title">Title</div>
<div class="text" contenteditable>
Full text<br>
Can be multiline and with vertical scroll
</div>
</div>
<div class="photos">
<div class="thumbnail">Thumbnail</div>
<div class="thumbnail">Thumbnail</div>
<div class="thumbnail">Thumbnail</div>
<div class="thumbnail">Thumbnail</div>
</div>
</div>
</div>
link to fiddle: https://jsfiddle.net/SkyLight/jxobz8qn/
The card has maximum width and height and Full text section (cyan one) can have pretty long content so that it should have scroll when needed. Thumbnails section can also have big amount of items so will also need to have scroll.
I know that overflow needs block to have height set in order to work but I can't figure out how to set it properly because the content should be limited mainly by Card's max size.
So can it be achieved with flexbox only or I'll need some other stuff? Would like to achieve the result with pure css.
Make the card element a flexbox container then use flex:1 on the body:
.card {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 50%;
min-width: 100px;
min-height: 0;
max-width: 80%;
max-height: 80%;
border: solid 1px black;
padding: 10px;
/* added */
display: flex;
flex-direction: column;
/**/
}
.photo {
background-color: silver;
margin-bottom: 10px;
aspect-ratio: 3;
}
.body {
display: flex;
flex:1; /* added */
min-height:0; /* added to make sure the content will shrink */
}
.content {
flex: 1;
display: flex;
flex-direction: column;
margin-right: 10px;
}
.title {
background-color: silver;
margin-bottom: 10px;
}
.text {
flex: 1;
background-color: cyan;
min-height: 0;
overflow: auto;
}
.photos {
width: 100px;
min-height: 0;
overflow: auto;
}
.photos * ~ * {
margin-top: 10px;
}
.thumbnail {
background-color: lightgreen;
aspect-ratio: 3;
}
<div class="card">
<div class="photo">Photo</div>
<div class="body">
<div class="content">
<div class="title">Title</div>
<div class="text" contenteditable>
Full text<br>
Can be multiline and with vertical scroll
</div>
</div>
<div class="photos">
<div class="thumbnail">Thumbnail</div>
<div class="thumbnail">Thumbnail</div>
<div class="thumbnail">Thumbnail</div>
<div class="thumbnail">Thumbnail</div>
</div>
</div>
</div>
Related
How do I get the .top_box to be fixed in the head of the .content?
With the current code, the .top_box always scrolls along with the .content.
.wrapper {
height: 160px;
display: flex;
flex-direction: column;
}
.title_container {
background: pink;
}
.content {
height: 0;
flex: auto;
position: relative;
overflow-y: auto;
overflow-x: hidden;
background-color: bisque;
}
.top_box {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 16px;
background: royalblue;
}
.scroll_fill {
height: 500px;
}
<div class="wrapper">
<div class="title_container">anyString</div>
<div class="content">
<div class="top_box"></div>
<div class="scroll_fill"></div>
</div>
</div>
You can just change the order of the HTML-Elements in the code and write .top before .item. If you do that, you can also remove most of the CSS because it’s unnecessary.
Here‘s a full example:
.box1 {
height: 600px;
display: flex;
flex-direction: column;
}
.box2 {
background: pink;
}
.box3 {
background-color: red;
}
.top {
width: 300px;
height: 5px;
background: blue;
}
.item {
height: 1000px;
}
<div class="box1">
<div class="box2">anyString</div>
<div class="box3">
<div class="top"></div>
<div class="item"></div>
</div>
</div>
Also a few other things: I wouldnt recommend just using divs and naming them like box1, box2, box3, .... Instead, give them names wich describe their use and meaning like wrapper, top_container, bottom_container, top_item, content, ...:
CSS Naming Conventions.
You can also use specific tags with semantic meanings: Sematic HTML5 Elements
Hope that helps
.wrapper {
height: 160px;
display: flex;
flex-direction: column;
}
.title_container {
background: pink;
}
.content {
height: 0;
flex: auto;
position: relative;
overflow: hidden;
background-color: bisque;
}
.contentInner {
height: 100%;
width: 100%;
overflow-y: auto;
overflow-x: hidden;
}
.top_box {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 16px;
background: royalblue;
}
.scroll_fill {
height: 500px;
}
<div class="wrapper">
<div class="title_container">anyString</div>
<div class="content">
<div class="top_box"></div>
<div class="contentInner">
<div class="scroll_fill"></div>
</div>
</div>
</div>
I want to create a layout where we have a header (responsive, with any height), footer (responsive, with any height), and content that fills the rest of space. Content should have two columns - first(right) that fits the content and second(left) that is very long and should have overflow with y-axis scrolling.
Detailed snipped with HTML and CSS attached.
I have problem with making them work inside of flexible height. I know how to make it work when I have only two columns, but with a responsive footer and header, I have problems.
I also have a code snippet inside of codepen
Thanks in advance for any help :)
html,
body {
height: 100%;
width: 100%;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
}
.column {
background-color: white;
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
color: black;
border: 5px purple solid;
}
.column-with-overflow {
overflow: auto;
max-height: 100%;
flex-grow: 1;
}
.column-with-overflow-content {
height: 1000px;
background-color: blue;
display: flex;
}
.columns {
display: flex;
flex-direction: row;
background-color: yellow;
width: 100%;
max-height: 100%;
}
.content {
background-color: blue;
flex-grow: 1;
}
.box {
text-align: center;
color: white;
display: flex;
justify-content: center;
}
.header {
background-color: green;
height: 60px; // assume that It's not known - any height
}
.footer {
background-color: red;
height: 60px; // assume that It's not known - any height
}
<div class="container">
<div class="box header">Header</div>
<div class="box content">
<div class="columns">
<div class='column column-with-overflow'>
<div class='column-with-overflow-content'>
box 1
</div>
</div>
<div class='column'>box 2</div>
</div>
</div>
<div class="box footer">Footer</div>
</div>
Set a fixed height to your .box.content div element.
And use min-height in .column-with-overflow-content insted of height
html,
body {
height: 100%;
width: 100%;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
}
.column {
background-color: white;
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
color: black;
border: 5px purple solid;
}
.column-with-overflow {
overflow: auto;
max-height: 100%;
flex-grow: 1;
}
.column-with-overflow-content {
min-height: 1000px; /* use min-height */
background-color: blue;
display: flex;
}
.columns {
display: flex;
flex-direction: row;
background-color: yellow;
width: 100%;
max-height: 100%;
}
.content {
background-color: blue;
flex-grow: 1;
}
.box.content { height: 100px; } /* set height to columns container */
.box {
text-align: center;
color: white;
display: flex;
justify-content: center;
}
.header {
background-color: green;
height: 60px; // assume that It's not known - any height
}
.footer {
background-color: red;
height: 60px; // assume that It's not known - any height
}
<div class="container">
<div class="box header">Header</div>
<div class="box content">
<div class="columns">
<div class='column column-with-overflow'>
<div class='column-with-overflow-content'>
box 1
</div>
</div>
<div class='column'>box 2</div>
</div>
</div>
<div class="box footer">Footer</div>
</div>
I can't seem to have a horizontally-scrolling div inside a flex column.
Codepen
.container { display: flex; margin: 20px; height: 300px; border: 1px solid blue; }
.side-nav { flex-shrink: 0; width: 100px; min-height: 100%; background: grey; }
.main { padding: 20px; }
.scrollable { overflow-x: auto; max-width: 100%; }
.long-content { width: 2000px; height: 50px; background: red; }
<div class='container'>
<div class='side-nav'>
</div>
<div class='main'>
<h1>Test</h1>
<div class='scrollable'>
<div class='long-content'>
This is supposed to scroll horizontally unless your window is super wide
</div>
</div>
<p>Some paragraph below the scrollable box</p>
</div>
</div>
If I change the max-width of .scrollable to px it would work, but I need it to fill the column.
What am I missing?
In my opinion, this is a Module"bug" (Wierd).
Anyway, one very simple solution is to use flex-basis (Instead of width).
Step 1 for main add width: 0;
.container {
display: flex;
margin: 20px;
height: 300px;
border: 1px solid blue;
}
.side-nav { flex-shrink: 0; width: 100px; min-height: 100%; background: grey; }
.main {
padding: 20px;
border: 5px dashed orange;
/* "new code" */
width: 0px;
}
.scrollable { overflow-x: auto; max-width: 100%; }
.long-content { width: 2000px; height: 50px; background: red; }
<div class='container'>
<aside class='side-nav'>
Aside
</aside>
<main class='main'>
<h1>Test</h1>
<div class='scrollable'>
<div class='long-content'>
This is supposed to scroll horizontally unless your window is super wide
</div>
</div>
<p>Some paragraph below the scrollable box</p>
</main>
</div>
Step 2 - main add flex-basis: 100%;
.container {
display: flex;
margin: 20px;
height: 300px;
border: 1px solid blue;
}
.side-nav { flex-shrink: 0; width: 100px; min-height: 100%; background: grey; }
.main {
padding: 20px;
border: 5px dashed orange;
/* "new code" */
width: 0px;
flex-basis: 100%;
}
.scrollable { overflow-x: auto; max-width: 100%; }
.long-content { width: 2000px; height: 50px; background: red; }
<div class='container'>
<aside class='side-nav'>
Aside
</aside>
<main class='main'>
<h1>Test</h1>
<div class='scrollable'>
<div class='long-content'>
This is supposed to scroll horizontally unless your window is super wide
</div>
</div>
<p>Some paragraph below the scrollable box</p>
</main>
</div>
One more option is to use width: 0; & flex-grow:1
.container {
display: flex;
margin: 20px;
height: 300px;
border: 1px solid blue;
}
.side-nav { flex-shrink: 0; width: 100px; min-height: 100%; background: grey; }
.main {
padding: 20px;
border: 5px dashed orange;
/* "new code" */
width: 0px;
flex-grow: 1;
}
.scrollable { overflow-x: auto; max-width: 100%; }
.long-content { width: 2000px; height: 50px; background: red; }
<div class='container'>
<aside class='side-nav'>
Aside
</aside>
<main class='main'>
<h1>Test</h1>
<div class='scrollable'>
<div class='long-content'>
This is supposed to scroll horizontally unless your window is super wide
</div>
</div>
<p>Some paragraph below the scrollable box</p>
</main>
</div>
I don't like any of those ideas - but this is life hh.
I have three elements currently vertically centered in a container through flex:
<div class="parent">
<div class="first">A</div>
<div class="second">B</div>
<div class="third">C</div>
</div>
with CSS:
.parent {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 800px;
}
Looking like:
I would like to change it so the first element is vertically centered and the other elements follow:
Ideally this could be done simply through flex but so far I cannot find a solution. Any help greatly appreciated.
If your elements have a fixed size, you could accomplish this with a wrapping div
which size is the same as the first element and let the following elements just overflow.
.parent {
height: 125px;
background-color: palegreen;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.item-container,
.item {
width: 200px;
height: 30px;
}
.item {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid red;
}
.second {
height: 50px;
}
<div class="parent">
<div class="item-container">
<div class="item first">A</div>
<div class="item second">B</div>
<div class="item third">C</div>
</div>
</div>
If you can change the HTML structure, it's possible: Put the second and third elements into a wrapper DIV and put that one into the first. Then center the first one (not necessarily with flex - see below) and apply position: relative to it, and apply position: absolute and according position settings to the wrapper. For details see the snippet below.
.parent {
height: 500px;
border: 1px solid blue;
}
.first {
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 100px;
width: 300px;
background: #ccc;
}
.wrap1 {
position: absolute;
top: 100%;
width: 100%;
height: auto;
border: 1px solid green;
}
.second {
background: #eee;
height: 50px;
}
.third {
background: #aaa;
height: 80px;
}
<div class="parent">
<div class="first">A
<div class="wrap1">
<div class="second">B</div>
<div class="third">C</div>
</div>
</div>
</div>
ADDITION: Actually it's also possible with flex:
.parent {
height: 500px;
border: 1px solid blue;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.first {
position:relative;
height: 100px;
width: 300px;
background: #ccc;
}
.wrap1 {
position: absolute;
top: 100%;
width: 100%;
height: auto;
border: 1px solid green;
}
.second {
background: #eee;
height: 50px;
}
.third {
background: #aaa;
height: 80px;
}
<div class="parent">
<div class="first">A
<div class="wrap1">
<div class="second">B</div>
<div class="third">C</div>
</div>
</div>
</div>
I am having some trouble keeping this svg, and flexbox buttons from scaling over each other when scaling down. I want to use flexbox so that I can control the buttons and SVG overlay over this hero shot at all time.
Is there a better way to accomplish this, or am I screwed lol?
Any recommendations would be appreciated.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.ob-hero-container {
position: relative;
}
.herobtn-container {
width: 80%;
max-width: 800px;
margin: 0 auto;
position: absolute;
top: 60%;
right: 0;
bottom: 0;
left: 0;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.herosvg-container {
width: 80%;
max-width: 800px;
margin: 0 auto;
position: absolute;
top: -20%;
right: 0;
bottom: 0;
left: 0;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.herobtn-wrapper {
border: 2px solid transparent;
flex-grow: 1;
}
.herobtn1 {
background-color: #000;
color: #fff;
padding: 10px;
/*margin: .1em;*/
text-align: center;
}
/* Tablet */
#media (min-width:30em) and (max-width:50em) {
.herobtn-wrapper {
flex-basis: 50%;
}
}
#media (max-width:50em) {
.herobtn-container {
position: relative;
width: 100%;
}
}
/* Mobile */
#media (max-width:30em) {
.herobtn-wrapper {
flex-basis: 50%;
}
}
<div class="ob-hero-container">
<!-- IMAGE BACKGROUND --><img src="https://s21.postimg.org/jp1vyijrb/sample.jpg" width="100%">
<!-- END IMAGE BACKGROUND -->
<div class="herosvg-container"><img src="http://svgshare.com/i/23M.svg" width="100%"></div>
<div class="herobtn-container">
<div class="herobtn-wrapper">
<div class="herobtn1">SHOP WOMEN'S</div>
</div>
<div class="herobtn-wrapper">
<div class="herobtn1">SHOP MEN'S</div>
</div>
<div class="herobtn-wrapper">
<div class="herobtn1">SHOP KIDS</div>
</div>
<div class="herobtn-wrapper">
<div class="herobtn1">WATCH VIDEO</div>
</div>
</div>
</div>
You can't allow for the .herosvg-container holding the svg text to be able to grow below the starting point for the buttons.
This change in the .herosvg-container rule will make them not overlap
top: 0; /* changed */
height: 60%; /* changed */
/* bottom: 0; removed */
Stack snippet
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.ob-hero-container {
position: relative;
}
.herobtn-container {
width: 80%;
max-width: 800px;
margin: 0 auto;
position: absolute;
top: 60%;
right: 0;
bottom: 0;
left: 0;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.herosvg-container {
width: 80%;
max-width: 800px;
margin: 0 auto;
position: absolute;
top: 0; /* changed */
height: 60%; /* changed */
/* bottom: 0; removed */
right: 0;
left: 0;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.herobtn-wrapper {
border: 2px solid transparent;
flex-grow: 1;
}
.herobtn1 {
background-color: #000;
color: #fff;
padding: 10px;
/*margin: .1em;*/
text-align: center;
}
/* Tablet */
#media (min-width:30em) and (max-width:50em) {
.herobtn-wrapper {
flex-basis: 50%;
}
}
#media (max-width:50em) {
.herobtn-container {
position: relative;
width: 100%;
}
}
/* Mobile */
#media (max-width:30em) {
.herobtn-wrapper {
flex-basis: 50%;
}
}
<div class="ob-hero-container">
<!-- IMAGE BACKGROUND --><img src="https://s21.postimg.org/jp1vyijrb/sample.jpg" width="100%">
<!-- END IMAGE BACKGROUND -->
<div class="herosvg-container"><img src="http://svgshare.com/i/23M.svg" width="100%"></div>
<div class="herobtn-container">
<div class="herobtn-wrapper">
<div class="herobtn1">SHOP WOMEN'S</div>
</div>
<div class="herobtn-wrapper">
<div class="herobtn1">SHOP MEN'S</div>
</div>
<div class="herobtn-wrapper">
<div class="herobtn1">SHOP KIDS</div>
</div>
<div class="herobtn-wrapper">
<div class="herobtn1">WATCH VIDEO</div>
</div>
</div>
</div>
You could wrap both the svg container and button container together. This ensures that they won't overlap.
Example:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.ob-hero-container {
position: relative;
}
.overlay {
width: 80%;
max-width: 800px;
position: absolute;
top: 0;
left: 0;
right: 0;
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
}
.herosvg-container {
margin-bottom: 1em; /* styling for demo */
}
.herobtn-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.herobtn-wrapper {
border: 2px solid transparent;
flex-grow: 1;
}
.herobtn1 {
background-color: #000;
color: #fff;
padding: 10px;
/*margin: .1em;*/
text-align: center;
}
/* Tablet */
#media (min-width:30em) and (max-width:50em) {
.herobtn-wrapper {
flex-basis: 50%;
}
}
#media (max-width:50em) {
.herobtn-container {
position: relative;
width: 100%;
}
}
/* Mobile */
#media (max-width:30em) {
.herobtn-wrapper {
flex-basis: 50%;
}
}
<div class="ob-hero-container">
<!-- VIDEO BACKGROUND -->
<!--
<video autoplay="" loop="" preload="auto" width="100%">
<source src="http://media.rackroomshoes.com/uploads/awhitten/obsw/bts-video.mp4" type="video/mp4; codecs=avc1.42E01E,mp4a.40.2" />Your browser does not support the video tag.</video>
-->
<!-- END VIDEO BACKGROUND -->
<!-- IMAGE BACKGROUND --><img src="https://s21.postimg.org/jp1vyijrb/sample.jpg" width="100%">
<!-- END IMAGE BACKGROUND -->
<div class="overlay">
<div class="herosvg-container"><img src="http://svgshare.com/i/23M.svg" width="100%"></div>
<div class="herobtn-container">
<div class="herobtn-wrapper">
<div class="herobtn1">SHOP WOMEN'S</div>
</div>
<div class="herobtn-wrapper">
<div class="herobtn1">SHOP MEN'S</div>
</div>
<div class="herobtn-wrapper">
<div class="herobtn1">SHOP KIDS</div>
</div>
<div class="herobtn-wrapper">
<div class="herobtn1">WATCH VIDEO</div>
</div>
</div>
</div>
<!-- /overlay -->
</div>