I have a situation where I want to display items on a web page vertically within columns. I want the number of columns to change based upon the available screen width. The items belong to groups. When there is enough screen size, I want display those in the same group in their own column. When the screen size is too narrow to display separate columns, I would like to combine the items into fewer columns. At the narrowest breakpoint, the items will be in one column. For now, a solution that supports two columns for wider screens and one column for narrow screens is sufficient.
There is another catch: the items have a global ordering, which must be preserved within columns.
Below is a snippet showing my current approach using float (based on this answer.) (I have included the global ordering (1-5) in the items to help illustrate.) This approach is close, but it has a problem where there is extra space between group items when they float below the last item in that group. (You might need to play with the media query breakpoint to see the behavior on your device.)
.items {
overflow: auto;
}
.item {
width: 50%;
}
.item.group-a {
float: left;
clear: left;
background-color: #FAF;
}
.item.group-b {
float: right;
clear: right;
background-color: #AAF;
}
#media only screen and (max-width: 400px) {
.item.group-a, .item.group-b {
float: none;
width: 100%;
}
}
<div class="items">
<div class="item group-a">
1. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla finibus ipsum quis nibh pretium commodo.
</div>
<div class="item group-b">
2. Quisque dolor ex, maximus non orci vel, luctus rhoncus lectus. Aliquam vulputate lacus et ipsum placerat commodo.
</div>
<div class="item group-a">
3. Cras gravida rhoncus elit, eu porttitor ipsum tempor at. Sed blandit pulvinar purus, eget pellentesque arcu rhoncus in.
</div>
<div class="item group-a">
4. Morbi accumsan, lectus a hendrerit congue, sapien dolor accumsan purus, eu iaculis nulla turpis ut sapien.
</div>
<div class="item group-b">
5. Aliquam elementum sapien ut dignissim lacinia. Etiam in nulla feugiat, porta massa at, tempor nulla. Suspendisse ullamcorper at ligula ut auctor.
</div>
</div>
In the production system, the number of items, group assignment, and ordering can change, so I cannot depend on the particular items or their ordering shown here. I will know the possible groups in advance.
Here are images of the behavior in case the snippet doesn't work for you. This first image shows the items combined into a single column for a narrow viewport. Note that the items are in order.
This second image shows the items split into two columns. Note that the the gap between items 2 and 5 is not intentional and is what I am trying to get rid of.
This is new development, so I'm not tied to any particular HTML or approach. I was attempting to accomplish this using only CSS for simplicity, but if the consensus is that JavaScript is necessary, that's okay. I saw some answers using flex order to re-order items, but I didn't see how I could design a system to support that generally when I don't know which items/groups/orders are coming out of the system.
At some point I would like to support more than two columns. Ideally, I would have a maximum of five groups/columns for the widest screens, then, as screens get narrower: three, two, and just one column. (There are business rules that dictate how groups can be combined.)
This answer offsetting the float doesn't work for me because the items are dynamic so I don't know in advance which floats might need offsetting. This answer about multi-col doesn't work because I must separate the items by their group. I am not just trying to layout a homogenous list of items in a columnar format.
Thanks!
If your container height can be set before hand, you have a solution using flex display.
Order is used to set the columns as you want, and a pseudo element is used as a spacer.
For a solution with more than 3 columns, since there are only 2 pseudos available, you would need extra elements to act as separators
.items {
overflow: auto;
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 90vh;
}
.item {
width: 50%;
}
.item.group-a {
background-color: #FAF;
order: 10;
}
.item.group-b {
background-color: #AAF;
order: 20;
}
.items:before {
content: "";
order: 15;
height: 100vh;
}
#media only screen and (max-width: 400px) {
.item.group-a, .item.group-b {
width: 100%;
}
.item.group-a {
order: 10;
}
.item.group-b {
order: 10;
}
}
<div class="items">
<div class="item group-a">
1. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla finibus ipsum quis nibh pretium commodo.
</div>
<div class="item group-b">
2. Quisque dolor ex, maximus non orci vel, luctus rhoncus lectus. Aliquam vulputate lacus et ipsum placerat commodo.
</div>
<div class="item group-a">
3. Cras gravida rhoncus elit, eu porttitor ipsum tempor at. Sed blandit pulvinar purus, eget pellentesque arcu rhoncus in.
</div>
<div class="item group-a">
4. Morbi accumsan, lectus a hendrerit congue, sapien dolor accumsan purus, eu iaculis nulla turpis ut sapien.
</div>
<div class="item group-b">
5. Aliquam elementum sapien ut dignissim lacinia. Etiam in nulla feugiat, porta massa at, tempor nulla. Suspendisse ullamcorper at ligula ut auctor.
</div>
</div>
Related
I am trying to create a background that auto adjusts in height as I add content.
If there is no content, the background should cover the entire screen, 100vh. As I add content the background should adjust in height until it reaches its minimum height of 100px. I have included an image to show demo what I am trying to achieve.
I have tried using min/max/100%/auto height properties and cant seem to find a solution.
I am using vue 3, typescript and css in my project.
Can someone please help me?
Using flexbox would give you exactly what you are asking for. In a nut shell what is happening is the parent container is using display flex which causes the children use flexbox properties. The .background div then has flex-grow : 1 which pretty much says grow as much as you can to fill the container. That means it will grow to fill the left over space of the parent depending on how much text there is.
.flex-container {
display: flex;
height: 100vh;
flex-direction: column;
}
.background {
background-color: blue;
flex-grow: 1;
}
<div class="flex-container">
<div class="background">
<h1>my background div</h1>
</div>
<div class="text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
finibus, odio vel scelerisque convallis, leo odio scelerisque urna, ut
scelerisque elit urna id quam. Etiam tempus pretium erat a semper.
Mauris consequat scelerisque ante id volutpat. Suspendisse convallis,
ipsum ut vehicula vehicula, lorem mauris porttitor enim, sollicitudin
ultrices lectus sem et ipsum. Morbi feugiat, lorem at viverra mattis,
neque enim vehicula turpis, blandit luctus eros eros ut arcu. Praesent
facilisis pharetra consectetur. Maecenas sagittis commodo felis, vitae
tristique risus. Phasellus fermentum varius turpis vel rhoncus. Nullam
aliquet nec risus non interdum. Sed nec magna pellentesque, facilisis
felis ac, cursus leo. Fusce et tortor magna. Fusce odio eros, varius non
placerat mattis, ullamcorper sed purus.
</div>
</div>
You can use your text container to hide the background underneath.
.container {
border: solid 1px grey;
background-color: red;
position: relative;
height: 250px;
}
.text {
position: absolute;
bottom: 0;
background-color: white;
width: 100%;
}
<div class="container">
<div class="text">
<p>Here is some text <br /> on multiple <br /> lines.</p>
</div>
</div>
For marketing banners, etc. it is desirable to keep the precise look of a page (or part thereof). That means all the margins, text sizes, image sizes, etc. The simplest way to do this is to use absolute XY positioning for each element, and then scale entire aggregate block (parent element) to fit the width of the device.
Rationale: Layouts like flexbox require a lot of tweaking to get "just right" and assumes that text size should be fixed as the device size changes. In reality, scaling the text with the device makes sense in many case (within a device category, like smartphones). At the same time, it's good to have the text in HTML, as opposed to exporting as an image (for SEO)
Is this possible to do with CSS? I have not found a resource on how to achieve this.
Yes - this kind of layout can be accomplished by using a foundation of viewport-percentage lengths (vw or vh units) so that your page scales based on the size of your browser window.
All you really need to make this work is to start your CSS with a viewport-percentage unit as the font-size of a root element (body, :root, or a wrapper div), and then style everything inside using em units - which will be based on the browser size.
One thing to keep in mind is that em units cascade based on the closest parent element with a font-size specified, so if you want a property to be sized based on the root 1vw without fonts affecting it, use rem units to size relative to the root.
Here's a very rudimentary example of a layout that will grow/shrink depending on the window width, but maintain its exact layout and positioning regardless.
:root {
font-size: 1vw;
}
.wrapper {
display: flex;
}
.side {
flex: 0 0 20rem;
font-size: 3em;
position: relative;
}
.side ul {
padding-left: 2em;
}
.side img {
position: absolute;
top: 20rem;
width: 16rem;
left: 2rem;
}
.content {
flex: 0 0 80rem;
font-size: 3em;
}
<div class="wrapper">
<div class="side">
<ul>
<li>List item</li>
<li>List item</li>
<li>List item</li>
</ul>
<img src="http://via.placeholder.com/350x150" />
</div>
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean sit amet felis vitae nulla efficitur mattis. Nulla cursus lectus ut libero molestie, in elementum dolor faucibus. Vivamus pretium pulvinar maximus. Quisque erat nunc, aliquet at eros id,
ultricies placerat dui. Nullam pellentesque euismod ligula, non viverra quam ullamcorper vel. Ut feugiat est ut felis consequat tempus. Aenean molestie mauris eget turpis tincidunt, a dictum orci malesuada. Maecenas semper interdum nulla, quis gravida
quam accumsan nec. Nunc gravida, eros in cursus vehicula, erat dolor porttitor tellus, ac congue felis ante non metus.
</div>
</div>
I am trying to make responsive one of my sites... :)
In standard view (pc), I have a div container called "article" containing more divs on 2 cols, all of these have width: 350px.
Resizing the screen, I want the divs into "article" are centered into it in a single col.
I have tried a lot of ways, including margin: 0 auto, display: inline-block, display: table, but does not works, and divs are always flotted to left of "article". :(
Using this method in media query:
left: 50%
margin-left: 175px;
It center the div when "article" has width: 707px (708 is just I need for divs on two cols including a few padding),
but reducing width under 707px value, the centering is losed because margin-left has a fixed value!
you only need to margin: 0 auto; your div, like so:
.container {background-color:red;}
.content {background-color:aqua;width: 350px;margin:10px auto;}
<div class="container">
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eleifend eu leo quis euismod. Phasellus blandit suscipit ipsum non pretium. In facilisis scelerisque sodales. Integer posuere nunc eget orci tincidunt, et dapibus dui porta. Duis pellentesque commodo mi, non congue erat imperdiet ac. Morbi facilisis accumsan dapibus. Quisque metus risus, ullamcorper ut faucibus ac, elementum in arcu. Aliquam vulputate sapien sed ullamcorper dignissim. Cras aliquet nisl nibh, a feugiat tortor pellentesque ac. Donec id mollis ante, sit amet ultricies velit.
</div>
</div>
I would start by using percents on your sub columns. Fixed widths will cause unwanted problems.
Then on your mobile layout, have your sub column go full width and remove the float. That will have the columns stack on top of each other.
.article .subColumn {
width:48%;
float:left;
}
#media screen only and (max-width:480px) {
.article subColumn {
float:none;
width:100%;
padding:0 25px;
}
}
I have a flex layout with two flex items, displayed as rows (flex-direction: column). The items should have a minimum height but they should maintain the same height it one of them needs to grow. See this JSFiddle and decrease the width of the result pane; this forces the second .component element to increase its height, but the height of the first .component element remains the same.
Is it possible to force the flex items to maintain the same height? Please note that the main thing in this is the stacking of the two .component elements, which I couldn't achieve without flex-direction: column; flex-direction: row would have made the same height possible but the stacking does not work.
Here is the result of what I have so far:
div {
border: 1px solid black;
box-sizing: border-box;
}
.container {
display: flex;
flex-direction: column;
align-content: stretch;
}
.component {
min-height: 300px;
}
.left {
margin-left: 50px;
margin-top: 50px;
margin-right: 100px;
background-color: lightyellow;
}
.right {
margin-left: 100px;
margin-top: -250px;
margin-right: 50px;
background-color: lightgreen;
}
<div class="container">
<div class="component left">
</div>
<div class="component right">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent sed orci scelerisque, scelerisque enim at, ullamcorper ipsum. Cras eget sapien mi. Aliquam ultrices, ligula ut mollis maximus, ligula massa imperdiet libero, at faucibus mauris ante non
magna. Sed ex lacus, efficitur sit amet neque ut, venenatis hendrerit libero. Suspendisse ornare orci mi. Nulla iaculis egestas libero, eu tincidunt urna tristique et. Quisque nec odio non elit molestie facilisis.
</p>
<p>
Vestibulum scelerisque justo urna, a semper nisi sollicitudin in. Cras congue enim eu euismod semper. Proin consequat gravida felis, quis tincidunt massa pulvinar quis. Morbi nec diam eget orci vestibulum malesuada. Sed volutpat metus eget mattis commodo.
Nulla facilisi. Praesent lectus mauris, consequat eu varius vitae, cursus vitae leo. Vivamus sagittis lacinia tortor eu ullamcorper. Integer eget velit magna. Duis vestibulum molestie posuere.
</p>
</div>
</div>
The flex equal height columns feature – which is the result of align-items: stretch, a default setting of a flex container – applies only to flex items on the same row.
It doesn't work for items in a multi-line flex container. This behavior is defined in the spec:
6. Flex Lines
In a multi-line flex container (even one with only a single line), the
cross size of each line is the minimum size necessary to contain the
flex items on the line (after alignment due to align-self), and the
lines are aligned within the flex container with the align-content
property.
In other words, when there are multiple lines in a row-based flex container, the height of each line (the "cross size") is the "minimum size necessary to contain the flex items on the line".
In addition, because align-items: stretch works along the cross-axis, the equal height columns feature is useless in flex-direction: column, where the cross-axis is horizontal.
To achieve equal height columns/rows across multiple lines consider a Javascript solution.
However, without knowing much about your overall objective, here's a simple way to achieve equal height rows in your current layout:
Add duplicate content in both divs. In the .component.left div, use visibility: hidden.
Revised Fiddle
You can just wrap those flexbox columns in another flexbox that's a row, there's no reason you can't have items be both flexboxes and flex items.
#container {
display: flex;
}
#container .col {
flex-grow: 1;
display: flex;
flex-direction: column;
background: grey;
}
<div id="container">
<div class="col">
asdf
asdf
asdf
</div>
<div class="col">
asdf
asdf
asdf
</div>
</div>
https://jsfiddle.net/1dp87bm2/1/
I need to implement a responsive table design that works in as many browsers as possible. The two left most cells (left/mid) will have static width while I need the right div to have a dynamic width based on the size of the current window.
This is how the markup looks like :
<div class="wrapper">
<div class="leftWrapper">
<div class="left">left</div>
<div class="mid">mid</div>
</div>
<div class="right">Lorem ipsum dolor sit amet, facilisi velit justo non. Pretium vestibulum nibh nonummy et a libero. Aptent consequat suscipit ridiculus leo pellentesque tempus, suspendisse pretium quis turpis. Euismod facilisi congue ab. Pretium ultricies non aliquam mi, cras sint, pede elit ligula aliquam in scelerisque ultricies, vitae dictum tincidunt sit, torquent eu et eros suspendisse. Voluptate nec curabitur et at nam non, diam vel, lorem nibh id condimentum a, laborum ornare, pede sem mattis. Numquam magna non metus sit fringilla, ligula quis cras, in lorem, praesent eros volutpat nisl vehicula tellus, egestas nullam. Pede aliquam donec.</div>
</div>
http://jsfiddle.net/mmZeN/.
How do I let right cell stay on the same line as the left and mid cell without using display: table-cell and at the same time litting it resize based on the width of the bowser?
I've made this from complete scratch, see if it's useful to you
Demo
<div class="wrapper">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
<style>
.left {
float: left;
width: 200px;
background-color:#0f0;
min-height: 200px;
}
.center {
float: left;
width: 120px;
background-color:#000;
min-height: 200px;
}
.right {
height: 200px;
background-color: #f0f;
margin-left: 320px;
}
</style>
Do not float the .right element and give it a margin the same width as the .leftWrapper
That is the beauty of the floats..
updated demo at http://jsfiddle.net/mmZeN/2/
If you have static values for left and middle one, you may specify using css and let other column to be percentage value. This should work in this case.
Updated: Get the px with of current placeholder(may be a DIV), deduct left and middle column width, then remain width ex: Xpx
Xpx/total width of container x 100
this value you may give as percentage.