I'm trying to build a UI which has the section be display:grid with a grid-template-columns: 1fr 3fr.
Then I have 2 block elements that should be placed in those columns (I used grid-column: 1/2 and grid-column: 2/3), respectively.
Now, my issue is that I wanted the block on the left (in the 1fr cell/area) to have a fixed-position. It's supposed to be a persistent navigation sidebar. However, when I used position: fixed, the block is removed entirely from the grid and so responsiveness doesn't really factor in anymore.
I tried nesting a container inside the main grid-item and giving that one the fixed-position, but when I adjusted my viewport to test, the fixed-container just overflowed/overlapped onto the 3fr block.
Any ideas on who to pull this off?
Thanks!
If you want the element to remain a grid item, then the answer is "you can't".
Once an element has position: absolute or position: fixed (which is a form of absolute positioning, with reference to the viewport), it takes on new characteristics:
the element is removed from the document flow
the element is removed from the grid formatting context
the element is no longer a grid item
So a grid item doesn't work well with fixed positioning.
However, you won't have a problem applying position: fixed to a grid container.
Consider managing your #left and #right elements separately. #left can be a fixed-position grid container. #right can be another grid container and remain in-flow.
Percentage padding / margin on grid item ignored in Firefox
Why doesn't percentage padding / margin work on flex items in Firefox and Edge?
Perhaps position:sticky instead.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
::before,
::after {
box-sizing: inherit;
}
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-gap: .5em;
}
aside {
padding: 0 .5em;
background: lightblue;
}
main {
grid-column: 2;
height: 500vh;
background: lightgreen;
}
aside div {
position: sticky;
top: 0;
}
<div class="grid">
<aside>
<div>
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
<li>item 6</li>
<li>item 7</li>
<li>item 8</li>
<li>item 9</li>
<li>item 10</li>
</ul>
</div>
</aside>
<main>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit provident, voluptatem, dolor eligendi quos harum reiciendis accusantium sapiente optio ad suscipit ullam, quibusdam aut ipsam laboriosam itaque eius officiis. Sapiente molestias vero aut
deleniti vitae cupiditate praesentium necessitatibus delectus, incidunt, cumque porro molestiae ipsa quas eveniet quisquam quod ipsam? Earum.</main>
</div>
The page still scrolls but the div in the sidebar remains "stuck" to the top
Hello i had this problem too, and the solution i came up with and it's working :)
just wrap the div that you want with a grid layout with another div lets call it parent, the parent div will be the grid element and the div inside will be with the position fixed!
.parent{
// This div will be from the grid children
}
.child {
position:fixed;
}
Related
This question already has answers here:
Font scaling based on size of container
(41 answers)
Closed 2 months ago.
Let's say I have a div with some small text in it.
The intention is that this text should fit into "only" one line. When the container width is big, the text should be justified and when the container width is small, the text should still be in one line and the font size should decrease to preserve being in one line. (Not hiding its over-flow)
I tried text-align: justify; but it doesn't work. since it does not justify the last line. (which in this case, the last line is actually the only line we have.)
Any help one this one is appreciated. Thanks in advance.
there!
If you really want to fit the text in one line, I would do something like this:
div {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1; /* no. of lines to be shown */
overflow: hidden;
/* general styling */
box-sizing: border-box;
width: 70%;
margin-inline: auto;
padding: 0.25em 0.5em;
background-color: #ccc;
}
p {
/* remove default margin */
margin: 0;
}
<div>
<p>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dicta odit corporis perferendis odio nesciunt nihil harum magni ipsam quidem saepe, iusto, praesentium impedit vel commodi exercitationem nam possimus architecto fugit.
<p>
<div>
However, if you don't want your text to be overflown and responsive, you can use the calc() operator to calculate the font-size based on the width of the div.
Alternatively, clamp() is also a good option to go with. But, you need to play around with the numbers.
You can read more about calc() and clamp() operations in MDN Docs.
I hope it helps! :)
I am trying to get my mind around flex box layout and now considering flex-direction: column option.
HTML
<div class="container">
<div class="item">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quaerat similique nihil, mollitia
voluptates iste eos atque unde repellendus iure voluptatibus nulla explicabo laboriosam, harum, eum dicta.
Maiores quia aliquid in.</div>
<div class="item">
Lorem
</div>
</div>
CSS
.container {
display: flex;
flex-direction: column;
}
.item{
flex: 1;
}
As long as our screen displays the first item div's text in multiple rows, the items end up with different main sizes (heights). It was rather surprising to me as row flex-direction in this case would hold the same main sizes of items (widths).
To find out how it happens, I delved into the spec.
9.2. Line Length Determination
2 Determine the available main and cross space for the flex items. For each dimension, if that dimension of the flex container’s content box is a definite size, use that; ... otherwise, subtract the flex container’s margin, border,
and padding from the space available to the flex container in that
dimension and use that value. This might result in an infinite value.
4 Determine the main size of the flex container using the rules of the formatting context in which it participates.
As far as I'm concerned, it is the very case when the available space in the main (vertical) dimension is an infinity value. So it puzzles me how it's possible to determine the container's main size (step 4), noting that sizes of the items are still uncalculated at this point (the container is a block element, so its height value is dependent on its children).
Can anybody provide some explanation and point me out to the place in the spec where our items finally get different height values?1
1: In accordance with the step 4 of 9.7. Resolving Flexible Lengths, main size of an item should be a fraction of its grow factor to the sum of the items' grow factors multiplyed by the free space (the container's height). We have the same grow factors, so why do we see different items heights?
You are running it a complex case where another specification need to be considered and also the min-height constraint.
When using flex:1 the browser is setting flex-basis: 0%. Pay attention to the % because all the trick is there. You have a percentage so you need a reference to resolve it and we are dealing with a height auto so the reference doesn't exist. At the end it's like you didn't set any flex-basis that's why you see no difference.
Now if you use flex-basis: 0px you will have a different behavior
.container {
display: flex;
flex-direction: column;
border: 1px solid;
}
.item {
flex: 1 1 0px;
border: 1px solid red;
min-height: 0;
}
<div class="container">
<div class="item">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quaerat similique nihil, mollitia voluptates iste eos atque unde repellendus iure voluptatibus nulla explicabo laboriosam, harum, eum dicta. Maiores quia aliquid in.</div>
<div class="item">
Lorem
</div>
</div>
Note that I have also introduced min-height: 0. Without it, nothing will happen because an element cannot shrink past its content size.
Now if you set flex-basis to 0px, each element will have an initial height equal to 0px so the height of the container will also be equal to 0px. End of the story! flex-grow and flex-shrink will do nothing since there is no positive or negative free space.
It's different when dealing with a row direction because the container width doesn't depend on its content and is full width. In such case you will have free space for the flex-grow and you end with equal width items.
The easiest way to understand what I want to achieve is in the attached image.
Essentially, I want to create a responsive layout comprising of 3 elements within a section - a header, a body, and a footer. On smaller screens (i.e. mobile) the 3 elements simply stack as you'd expect.
However, on larger desktop screens, I want the elements to split into 2 columns - the header and footer on the left, and the body on the right.
The problem is I'm actually not sure I can create this behaviour with CSS alone.
The best I can achieve ends up with the footer element staying in line with the bottom of the body element, like the below image (I understand why, I just want to figure out a way around this.)
I've tried a few methods using floated elements, as well as flexbox solutions and playing with the ordering, but with no success. I even tried some grid stuff, although my knowledge of grid isn't great so I may have missed something.
I know that I could use JS to do something such as moving the header and footer within a single parent element, or back out again, depending upon screen size. But I'm hoping there's a CSS-only way to achieve this, as that doesn't seem very elegant.
Thanks in advance for any suggestions!
Use css-gridwith the use of `grid-template-areas" to define the placement of a specific section as the example below. To allow the body section to extend further then the header and footer, you just need to use 3 rows.
body {
display: grid;
margin: 0;
padding: 20px;
grid-gap: 20px;
}
section {
background-color: red;
color: white;
padding: 10px;
}
#header {
grid-area: header;
}
#body {
grid-area: body;
}
#footer {
grid-area: footer;
}
#media only screen
and (max-width: 480px) {
body {
grid-template-areas:
"header"
"body"
"footer";
}
}
#media only screen
and (min-width: 481px) {
body {
grid-template-areas:
"header body"
"footer body"
". body";
grid-template-columns: 4fr 6fr;
}
}
/* for styling purpose only */
#body {
min-height: 70vh;
}
<section id=header>Header</section>
<section id=body>Body</section>
<section id=footer>Footer</section>
I have used CSS Grid to achieve this, I know you already acheived in Mobile version so I'm just sharing the demo code for Desktop Version. CSS Grid is really powerful you can create complex layout in minutes.
.outer{display: grid; grid-template-areas: 'header body' 'footer body' 'footer body';
}
.header{width: 100%; grid-area: header; height: 50vh; background-color: yellow;}
.body{grid-area: body; background-color: red; }
.footer{grid-area: footer; height: 50vh; background-color: violet;}
<div class='outer'>
<div class='header'> HEADER</div>
<div class='body'> body</div>
<div class='footer'> Footer</div>
</div>
using a div with zero width and height and margin negative of the div the result can be achieved.
the purple is a div with display flex and a normal
orientation with flex wrap turned on. orange is the footer. it has a
negative margin to equivalent to the body height plus the. the thing in yellow
is a div with width and height 0 and margin bottom equivalent to its height
of the body. when the page is wide enough both the body and and the yellow
div are moved to the side and the negative margin of the footer makes it go up to just
bellow the header at the bottom is an in browser version, the yellow square is there to indicate
the location of the padding div.
I know we are in 2021, but old good simple floats can be used for this task
#media (min-width: 480px) {
div {
display: flow-root;
border: 1px #ccc dashed;
}
header, footer {
width: 40%;
float: left;
}
main {
float: right;
width: calc(60% - 10px);
}
}
div > * {
box-sizing: border-box;
color: #fff;
background: #eb0022;
padding: 10px;
margin-bottom: 10px;
}
<div>
<header>header</header>
<main>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eos tempore doloremque, illum praesentium atque cumque nulla, dolorum obcaecati quod recusandae itaque pariatur unde soluta blanditiis repudiandae perspiciatis deserunt fuga commodi.</p>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eos tempore doloremque, illum praesentium atque cumque nulla, dolorum obcaecati quod recusandae itaque pariatur unde soluta blanditiis repudiandae perspiciatis deserunt fuga commodi.</p>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eos tempore doloremque, illum praesentium atque cumque nulla, dolorum obcaecati quod recusandae itaque pariatur unde soluta blanditiis repudiandae perspiciatis deserunt fuga commodi.</p>
</main>
<footer>footer</footer>
</div>
I tried to find a question same as mine but I couldn't find one. Probably because I don't know the right words to explain my question.
Anyways, let's say I have a div that has dynamically generated content and below the div there is a button. I want to have some white space between the div and the button (about 200px). Here is a diagram to illustrate:
##############################
# #
# Div with dynamically #
# generated content #
# #
##############################
↑
200px
↓
##########
# Button #
##########
However, if the div's height gets larger, I want the space between the div and button to collapse until a certain minimum distance. So basically the button should not move while the div gets larger and larger until a certain distance between the div and button (for example 5px).
I know questions should show some attempt to answer the question but I don't know where to start. I was thinking to absolutely position the button relative to the parent but then the div won't push it down. I know I should give the button a margin-top:5px;.
I think you can do this with Flexbox and min-height on wrap div and then you just add margin-top on button
So this is how it looks with short text
.wrap {
min-height: 100px;
border: 1px solid black;
width: 200px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
}
button {
margin-top: 20px;
}
<div class="wrap">
<div class="inner">lorem</div>
<button>BTN</button>
</div>
But when you increase text size wrap div increases its height but button still keep its margin-top distance to text.
.wrap {
min-height: 100px;
border: 1px solid black;
width: 200px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
}
button {
margin-top: 20px;
}
<div class="wrap">
<div class="inner">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorem ut ducimus beatae veniam quam tenetur maxime, commodi quo, doloribus inventore amet blanditiis nihil voluptates voluptatum reprehenderit nam facilis assumenda consequuntur eius, qui dolorum id repudiandae.</div>
<button>BTN</button>
</div>
You can do this using jquery and use conditional statements to evaluate the distance between the elements. Something like:
var el1 = $("#firstElement").position();
var el2 = $("#secondElement").position();
if (el1.bottom > (el2.top+5)) {
$("#secondElement).animate({ top: el2.bottom+5 });
}
I ended up finding another solution that satisfies my problem and it was so simple. I just have to wrap the expanding div with another div that has a min-height. So the expanding div will expand and not affect the position of the button until it goes past the min-height of its parent.
Nenad's answer was good as well but this one is more compatible cross-browser.
.wrap {
min-height:100px;
}
button {
margin-top:5px;
}
<div class="wrap">
<div class="inner">
Lorem ipsum dolor sit amet.
</div>
</div>
<button>Click Here</button>
I have written a Knockout binding for a MegaMenu which has a hamburger component
The hamburger contains a bunch of Categories and items within these Categories
The Categories act as a header and are bolded. They then display their items underneath indented slightly
Categories and Items are just strings retrieved from a database
The rules of the hamburger are as follows:-
Don't split a Category across columns
Use 3 columns first before scrolling. i.e Don't fill only two columns and have a scroll bar (vertical)
Even up the columns as much as possible
3 columns max
The hamburger has a max height restriction
Categories are to be ordered alphabetically -
An example of the ordering is a follows:-
Assume I have the following Categories (ignore the items within them as it is the categories that are ordered)
Dogs, Cars, Cats, Beds, Furniture, Hobbies, Homes, Gyms, Horses
and if these were split across 3 columns they would be rendered as follows
Col 1 Col 2 Col 3
----- ----- -----
Beds Dogs Hobbies
Cars Furniture Homes
Cats Gyms Horses
I am able to construct html lists as follows:-
<div>
<ul>
<li>Beds
<ul>
<li>Item 1</li>
<li>Item 2
</ul>
</li>
<li>Cars
<ul>
<li>Item 1</li>
</ul>
</li>
<li>Cats
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</li>
<li>Dogs
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</li>
</ul>
</div>
Can I use pure css to adjust it in the hamburger columns according to my rules?
That way I can avoid the messy looping etc that I am currently doing in my html
Your best bet is to use column layout with break-inside: avoid
From: https://css-tricks.com/almanac/properties/b/break-inside/
Fortunately, you can tell the browser to keep specific elements
together with break-inside.
-webkit-column-break-inside: avoid; /* Chrome, Safari, Opera */
page-break-inside: avoid; /* Firefox */
break-inside: avoid; /* IE 10+ */
I've made an example here
http://codepen.io/HerrSerker/pen/obgddJ
.outer {
-moz-columns: 3;
-webkit-columns: 3;
columns: 3;
display: block;
}
.outer > li {
display: block;
padding-top: 30px;
-webkit-column-break-inside: avoid;
/* Chrome, Safari, Opera */
page-break-inside: avoid;
/* Firefox */
break-inside: avoid;
/* IE 10+ */
}
.outer > li > span {
text-decoration: underline;
}
.inner {
width: 200px;
display: block;
text-decoration: none;
}
.inner > li {
display: block;
padding-left: 10px;
padding-top: 3px;
}
.wrapper {
width: 600px;
margin: 0 auto;
max-height: 400px;
overflow-y: auto;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
<div class="wrapper"><ul class="outer">
<li><span>Lorem ipsum dolor.</span>
<ul class="inner">
<li>Fuga, ratione blanditiis commodi.</li>
<li>Obcaecati dicta ut, pariatur!</li>
<li>Earum, illum sapiente enim.</li>
</ul>
</li>
<li><span>Vel, ratione cum!</span>
<ul class="inner">
<li>Lorem ipsum dolor sit.</li>
<li>Accusamus, odio ipsum nemo!</li>
<li>Molestiae unde natus odio.</li>
<li>Lorem ipsum dolor sit.</li>
<li>Corporis, tempora nisi minus.</li>
</ul>
</li>
<li><span>Aliquid, tenetur, similique.</span>
<ul class="inner">
<li>Lorem ipsum dolor sit.</li>
<li>Repellendus repellat placeat odit!</li>
</ul>
</li>
<li><span>Quibusdam, necessitatibus aliquid.</span>
<ul class="inner">
<li>Lorem ipsum dolor sit.</li>
<li>At nisi, quas veritatis!</li>
<li>Perferendis laudantium nesciunt dolor!</li>
<li>Distinctio quidem veniam impedit!</li>
</ul>
</li>
<li><span>Sed, quam, beatae.</span>
<ul class="inner">
<li>Lorem ipsum dolor sit.</li>
<li>Voluptates temporibus provident dolores.</li>
<li>Explicabo non minus ullam!</li>
<li>Tenetur, molestias, debitis. Voluptatum.</li>
<li>Quibusdam incidunt unde, laboriosam!</li>
<li>Fugiat perferendis eligendi, dignissimos.</li>
</ul>
</li>
<li><span>Lorem ipsum.</span>
<ul class="inner">
<li>Lorem ipsum dolor sit.</li>
<li>Perspiciatis, a dolore officia!</li>
</ul>
</li>
<li><span>Voluptatum, ipsum?</span>
<ul class="inner">
<li>Lorem ipsum dolor sit.</li>
<li>Odit, aliquam voluptates alias!</li>
</ul>
</li>
<li><span>Dolorem, quos!</span>
<ul class="inner">
<li>Lorem ipsum dolor sit.</li>
<li>Quae quos quas, fugit?</li>
</ul>
</li>
<li><span>Cum, excepturi.</span>
<ul class="inner">
<li>Lorem ipsum dolor sit.</li>
<li>Libero distinctio, necessitatibus laborum!</li>
</ul>
</li>
<li><span>Blanditiis, harum.</span>
<ul class="inner">
<li>Lorem ipsum dolor sit.</li>
<li>Corporis fuga accusamus, ab?</li>
</ul>
</li>
</ul>
</div>
Is this compatible? See here: http://caniuse.com/#feat=css-grid
As for the sorting: you cannot do this with CSS You have to do it in HTML or with JS
Can I use pure css to adjust it in the hamburger columns according to my rules?
No, CSS cannot perform the required even-distribution arithmetics. You're stuck with pre-formatting in HTML in this case.
You can set the value display:table to your parent div , and then set display:table-cell to your children items.That's not going to break your columns.
I think I can achieve what you want using css column:
ul{
...
column-gap: 2em;
-webkit-column-count: 3;
-moz-column-count: 3;
column-count: 3;
}
Demo: http://jsfiddle.net/pg2xy9h2/3/
I don't understand how it is possible to have Even up the columns as much as possible and a dynamic number of columns. Even up is a division calculation, how can you perform a division if the divisor is unknown?