I'm trying to use grid layout to create two columns. The right column has a fixed width but the left one should take whatever's left out. However, the problem is that when the content is too long, it extends the left column and causes a horizontal scrollbar in the container.
Now I can achieve this with other methods like calc but I'm trying to learn grid layout.
Here's a fiddle to demonstrate: https://jsfiddle.net/pta2c7um/
Ideally I would want the long title to get truncated respecting the grid structure.
Solution:
#ticket-viewer .list li{
/* grid-template-columns: auto 80px; */
grid-template-columns: minmax(0, 1fr) 80px;
padding: 1rem;
cursor: pointer;
}
Working example:
.list{
margin: 0;
padding: 0;
}
.list li {
padding: 0.8rem 0;
position: relative;
}
.list li small {
color: #777777;
}
.list li .content {
padding: 0 !important;
}
.list li .right-assist {
text-align: right;
}
.list.left-assist li, .list.right-assist li {
display: grid;
}
.list.right-assist li {
grid-template-columns: auto 40px;
}
.list.dividers li:before {
content: "";
position: absolute;
height: 1px;
background: #CCC;
bottom: 0px;
left: 0;
right: 0;
}
#ticket-viewer{
border: 1px solid #CCC;
display: flex;
}
#ticket-viewer .list{
width: 40%;
height: 560px;
overflow-y: auto;
border-right: 1px solid #CCC;
}
#ticket-viewer .list li{
/* grid-template-columns: auto 80px; */
grid-template-columns: minmax(0, 1fr) 80px;
padding: 1rem;
cursor: pointer;
}
.truncate {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
<div id="ticket-viewer">
<ul class="list right-assist dividers">
<li data-id="1" class="">
<div class="content"><span class="truncate">Test</span><small>Bug/Error on Website</small></div>
<div class="right-assist">Resolved</div>
</li>
<li data-id="2" class="active">
<div class="content"><span class="truncate">This is a very very long subject</span><small>Feature Request</small></div>
<div class="right-assist">Resolved</div>
</li>
</ul>
</div>
Explanation:
grid-template-columns: minmax(0, 1fr) 80px; step-by-step explanation:
Define two columns.
The last has fixed 80px width;
The first occupies remaining space.
minmax(0, ..) is used to tell browser to shrink width of column, if its content is wider than 1fr (i.e. 1 fraction of remaining space).
More info on MDN
Related
I have 2 containers. one for pictures and one for the table.
I want each container to change its height depending on the number of pictures and the number of table rows.
The upper picture's container should expand up to 2 rows (I did it with max-height) and become scrollable if there is a third row or more.
The bottom table's container should expand until the rest of the screen's height and then become scrollable.
BUT, if the picture's container has one row I want the table to expand up to the maximum height.
ALSO, I don't want the picture's second row to be cut by the table (unfortunately this is what happening right now).
This is what I did so far, close to the desired behavior but still not working as I wanted. I prefer to use only CSS for the solution.
here is my CodePen
HTML:
<div class="main">
<div class="pic-container">
<div class="pic">picture</div>
<div class="pic">picture</div>
<div class="pic">picture</div>
<div class="pic">picture</div>
<div class="pic">picture</div>
<div class="pic">picture</div>
<div class="pic">picture</div>
</div>
<div class="table-container">
<div class="table">
<table>
<tbody id="tbody">
<tr><td>my</td><td>life</td><td>for</td><td>Auir</td</tr>
<tr><td>my</td><td>life</td><td>for</td><td>Auir</td</tr>
<tr><td>my</td><td>life</td><td>for</td><td>Auir</td</tr>
<tr><td>my</td><td>life</td><td>for</td><td>Auir</td</tr>
<tr><td>my</td><td>life</td><td>for</td><td>Auir</td</tr>
</tbody>
</table>
</div>
</div>
</div>
css:
.main {
height: 600px;
width: 800px;
background: pink;
display: flex;
flex-direction: column;
}
.pic-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
overflow: auto;
max-height: 304px; /* 2 pic + borders*/
}
.table-container {
background-color: lightsalmon;
flex-grow: 1;
max-height: calc(600px - 152px);
}
.pic {
background: lightblue;
height: 150px;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #000;
}
.table {
overflow: auto;
height: 100%;
}
table, td, th {
border: 1px solid black;
}
td {
padding: 10px;
}
table {
width: 100%;
position: relative;
border-collapse: collapse;
overflow: auto;
}
the table goes over the second picture row - bad
this is how I want it to behave -> any idea?
example of how it behaves when there is one row - good
This works for me. The most important part is changing the main div display form flex to grid: display: grid; grid-template-rows: min-content auto; And move overflow: auto; from the table tag to table-container class.
.main {
height: 600px;
width: 800px;
background: pink;
display: grid;
grid-template-rows: min-content auto;
}
.pic-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
overflow: auto;
max-height: 304px; /* 2 pic + borders*/
}
.table-container {
background-color: lightsalmon;
overflow: auto;
}
.pic {
background: lightblue;
height: 150px;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #000;
}
.table {
height: 100%;
}
table, td, th {
border: 1px solid black;
}
td {
padding: 10px;
}
table {
width: 100%;
position: relative;
border-collapse: collapse;
overflow: auto;
}
Stackblitz Demo - https://stackblitz.com/edit/angular-ivy-lhtjgj?file=src/app/app.component.html
How do I add row-gap to provide spacing between each of these "boxed" elements within the *ngFor loop?
I do not want to use margin-top because that will add extra padding to the top of the first "boxed" element (same goes for margin-bottom with the last "boxed" element).
I tried to add a display: grid to the 'wrapper' div, but then overflow: hidden gets "ignored".
.box{
border: .1vw solid;
padding: 3vw;
}
.label{
white-space: nowrap;
overflow: hidden;
font-size: 5vw;
}
<div *ngFor="let x of documents">
<div class="box">
<div class="label">
Some ridiculously long text entered by the user
</div>
</div>
</div>
if you are using row-gap then add grid-template-rows too.
thats is,
grid-template-rows:auto auto;
row-gap:3vw;
display: grid;
Similarly,
if you are using column-gap then add grid-template-rows too.
thats is,
grid-template-columns:auto auto;
column-gap:3vw;
display: grid;
This will example to worked
.content[_ngcontent-oux-c40] {
padding: 3vw;
grid-template-rows: auto auto;
row-gap: 3vw;
display: grid;
}
result:
The whole screenshot
You need to apply the grid to your content container if you want a gap between the .iconandlabelcontainer .
Then it's just adding row-gap to your parent container.
requireddocumentsname {
font-family: var(--pcwidefontnormal2);
font-size: 5vw;
white-space: nowrap;
color: var(--pcblue);
}
.iconandlabelcontainer{
height: min-content;
border: .1vw solid blue;
font-size: 5vw;
white-space: nowrap;
overflow: hidden;
padding: 3vw;
}
.iconandlabel{
white-space: nowrap;
display: grid;
grid-template-rows: 1fr;
align-items: center;
width: 400px;
}
.content{
padding: 3vw;
display: grid;
row-gap: 30px;
justify-content:center;
margin: 0;
}
Grid is probably the best way to go, but FYI, you can solve the problem you describe with margins this way:
.box{
border: .1vw solid;
padding: 3vw;
margin-top: 3vw;
}
.box:first-child {
margin-top: 0;
}
Similarly, you can use the :last-child pseudocode to exclude the last box from a margin-bottom setting.
I tried to move the grid at center of the page, I dont know why it doesn't work
I looked a lot of example, I see people using this:
justify-content: center;
Even if I tried it and it doesn't work.
Here's my code
ul {
list-style-type: none;
background-color: silver;
padding: 10px;
text-align: center;
margin: none;
}
p {
text-align: center;
padding: none;
}
li {
display: inline;
padding: 10px;
}
a {
color: yellow;
}
.testing {
padding: 150px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 10px;
/* next comment was fixed to meet syntax in a plain style sheet */
justify-content: center;
/* its not moving to the center of the page*/
}
.testing div {
width: 225px;
height: 225px;
background-color: blue;
}
<ul>
<li><a href=" ">Home</a ></li>
<li><a href="#news">News</a ></li>
<li><a href="#contact">Contact</a ></li>
</ul>
<p>hellow world</p >
<div class = "testing">
<div></div>
Just change padding: 150px; to padding: 50%;, on .testing ('testing' class).
This should work.
Best regards,
Brhaka
The grid is centered, you just gave it 3 equal columns but only one child element, so the div is showing in the left-most column of the grid. If you change the CSS to grid-template-columns: 1fr or define a template area in the center it will display as you expected, but having only one column begs the question of why you are using a grid layout to begin with. What kind of layout are you trying to build? Maybe a flexbox solution would better fit your needs?
The image is an img tag and needs to be stretched as a background image over two areas 'img' and 'content'. The text has to go above the stretched image in the 'content' area. Simple but how? I can't find any obvious answers online.
.media {
border: 2px solid #f76707;
border-radius: 5px;
background-color: #fff4e6;
width: 100%
}
.media {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-areas: "img content";
margin-bottom: 1em;
}
.image {
grid-area: img;
background-color: #ffd8a8;
}
.text {
grid-area: content;
padding: 10px;
}
<div class="media">
<img class="image" src="https://loremflickr.com/500/200" />
<div class="text">This is a media object example.
We can use grid-template-areas to switch around the image and text part of the media object.
</div>
</div>
Modify your code as follows:
.media {
border: 2px solid #f76707;
border-radius: 5px;
background-color: #fff4e6;
width: 100%
}
.media {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-areas: "img content";
margin-bottom: 1em;
}
.image {
grid-area: img;
background-color: #ffd8a8;
}
.text {
grid-area: content;
padding: 10px;
}
.media {
background-image: url("https://loremflickr.com/700/200");
background-repeat: no-repeat;
height: 150px;
}
<div class="media">
<div class="text">This is a media object example. We can use grid-template-areas to switch around the image and text part of the media object.
</div>
</div>
Here is a screenshot of the output:
There are many ways to get the desired result.
You could also make the image a background of the DIV rather than having an IMG tag inside the DIV.
But I sticked to your code below and just added CSS to place the text DIV on top of the image and stretch the image to 100% with hidden overflow.
.media {
border: 2px solid #f76707;
border-radius: 5px;
background-color: #fff4e6;
width: 100% display: grid;
grid-template-columns: 1fr 1fr;
grid-template-areas: "img content";
margin-bottom: 1em;
overflow: hidden;
}
.image {
grid-area: img;
background-color: #ffd8a8;
width: 100%;
float: left;
}
.text {
grid-area: content;
padding: 10px;
position: absolute;
top: 10px;
left: 10px;
color: white;
text-shadow: 1px 1px 2px black;
box-sizing: border-box;
}
<div class="media">
<img class="image" src="https://loremflickr.com/500/200" />
<div class="text"><b>This is a media object example.
We can use grid-template-areas to switch around the image and text part of the media object.</b> </div>
</div>
I think, if there is just one part of the page at the background of the page, you should create a style. Then look at the backgammon tag select whatever you want,Later, the ID will have it in created anything on the page, for example
Panel, td, div,.... get it there.
You do not need to add any image.
Have you tried position: absolute on the text div?
I figured it out if anyone stumbles across it: (make sure you preview with full page)
#container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 100px;
grid-template-areas: "empty text" "mobile mobile";
}
#container img {
grid-column: 1 / span 2;
grid-row: 1 / span 1;
width: 100%;
overflow: hidden;
}
#container p {
grid-area: text;
color: red;
align-self: center;
justify-self: center;
z-index: 1;
}
#media (max-width: 768px) {
#container p {
grid-area: mobile;
color: red;
align-self: center;
justify-self: center;
z-index: 1;
}
}
<div id="container">
<img src="https://loremflickr.com/500/200">
<p>SOME TEXT OVER IMAGE</p>
</div>
I'm using flexbox to create a basic layout for a web application. I want there to be a menu across the top and, below that, a primary content area on the left and a secondary content area on the right, both of which vertically fill the space left over below the menu. If just the content areas are included in the HTML, the stretch covers everything. When I include the menu, however, I end up with a lot of white space between the menu and content areas.
In the JS fiddle, I added a little JavaScript to remove the menu when you click on either of the links to give a better idea as to how much white space (1rem) I'd like between the menu and the two content areas.
Can this be achieved using flex? Thanks!
$(document).ready(function() {
$("a").click(function() {
$(this).closest(".main-menu").remove();
})
})
html {
height: 100%;
}
body {
display: flex;
min-height: 100%;
width: 100%;
margin: 0;
padding: 0;
border: 0;
flex-wrap: wrap;
align-content: stretch;
}
.main-menu {
width: 90%;
margin: 1rem calc(5% - 1px) 1rem calc(5% - 1px);
padding: 1rem;
border: 1px dashed black;
align-self: flex-start;
}
.main-menu ul {
margin: 0;
border: 0;
padding: 0;
display: inline;
}
.main-menu ul li {
margin: 0;
border: 0;
padding: 0;
display: inline;
}
.primary-stuff {
margin: 1rem 1rem 1rem calc(5% - 1px);
width: calc(75% - 1rem - 1px);
border: 1px dashed black;
}
.secondary-stuff {
margin: 1rem calc(5% - 1px) 1rem 1rem;
width: calc(15% - 1rem - 1px);
border: 1px dashed black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="main-menu">
<ul>
<li><a>Link 1</a></li>
<li><a>Link 2</a></li>
</ul>
</div>
<div class="primary-stuff"></div>
<div class="secondary-stuff"> </div>
<div style="position:absolute;background:#FFC; width: calc(5% - 1px); height: 100%; left: 0;"></div>
<div style="position:absolute;background:#FFC; width: calc(5% - 1px); height: 100%; right: 0; top: 0;"></div>
<div style="position:absolute;background:#FFC; height: 1rem; width: 100%; right: 0; top: 0;"></div>
<div style="position:absolute;background:#FFC; height: 1rem; width: 100%; right: 0; bottom: 0;"></div>
Fiddle:
https://jsfiddle.net/don01001100/kdg04ubr/
You can't really do this with flexbox because of the way align-content works with wrap.
However, the layout is simple with CSS Grid layout:
body {
display: grid;
grid-template-columns: 75% 1fr;
grid-template-rows: auto 1fr;
grid-gap: 1rem;
min-height: 100vh;
}
nav {
grid-column: 1 / -1;
}
/* non-essential decorative styles */
body { margin: 0; padding: 1rem 2rem; }
nav { background-color: lightgreen; padding: 1rem; }
.primary-stuff { background-color: lightblue; }
.secondary-stuff { background-color: orange; }
* { box-sizing: border-box; }
<nav>
<a>Link 1</a>
<a>Link 2</a>
</nav>
<div class="primary-stuff"></div>
<div class="secondary-stuff"> </div>
Also, all those calculations you have for margins are not necessary. Here's an easy solution that will simplify your code: Flexbox: 4 items per row
You might find that the Grid Layout is a better fit for this type of layout, as it provides a cleaner method of arranging elements in the way you require, without the need for additional HTML markup.
You could achieve the layout you require using CSS-grid as follows:
html {
height: 100%;
}
body {
/* Cause grid to fill vertical space */
height:100%;
/* Prevent overflow due to padding */
box-sizing:border-box;
/* Use grid display type */
display: grid;
/* Tells grid to cause second row to fill
avaible/remaining vertical space */
grid-template-rows: auto 1fr;
/* Define the grid layout, in terms of areas
that are distributed between 3 colums and
2 rows */
grid-template-areas:
"menu menu menu"
"primary primary secondary";
/* Specify spacing between grid elements */
grid-gap: 1rem;
margin: 0;
padding: 1rem;
background:grey;
}
.main-menu {
background: pink;
/* Accociate the main-menu with the menu area
of your grid-template-areas defined above */
grid-area: menu;
}
.main-menu ul {
margin: 0;
padding: 0;
display: inline;
}
.main-menu ul li {
margin: 0;
padding: 0;
display: inline;
}
.primary-stuff {
background: lightblue;
/* Accociate the primary-stuff with the primary area
of your grid-template-areas defined above */
grid-area: primary;
}
.secondary-stuff {
background: lightgreen;
/* Accociate the secondary-stuff with the secondary area
of your grid-template-areas defined above */
grid-area: secondary;
}
<div class="main-menu">
<ul>
<li><a>Link 1</a></li>
<li><a>Link 2</a></li>
</ul>
</div>
<div class="primary-stuff">
primary content
</div>
<div class="secondary-stuff">
secondary content
</div>