Is this layout possible without subgrid and without repeating hardcoded values? - css

I have the layout in this sandbox. The requirements are that the "Title Text", "More Options" and "Search" areas are fixed at the top of the screen and do not move when scrolling, that "Title Text" and "Search" are aligned together, and that the container height of these two is a controlled hardcoded value (53px). Below the sticky headers there should be two columns of normal content flow, as shown in the sandbox.
I am using grid as such:
grid-template:
". header-main header-right ." 53px
". header-main content-right ." auto
". content-main content-right ." auto
/ 0.5fr 1fr 1fr 0.5fr;
"Title Text" and "More Options" are both grouped under a div which has header-main as its grid area, like this:
<div class="HeaderMain">
<div class="Wrapper">
<h2>Title text</h2>
</div>
<div>More Options</div>
<div>More Options</div>
<div>More Options</div>
<div>More Options</div>
<div>More Options</div>
<div>More Options</div>
</div>
"Search" is under a div that has header-right as its grid area. I give sticky properties to header-right and header-main.
For the final requirement, to have "Title Text" aligned with "Search", I wrap "Title Text" in a Wrapper div, and give it the same height of the row, 53px. Both Wrapper and HeaderRight have display: flex; align-items: center; for vertical alignment.
This works fine, but my issue is that I need to repeat the hardcoded value 53px in two places. Of course I can put it in a css variable, but I am wondering if there is a cleaner solution.
In this sandbox (firefox only), I solve it using a subgrid, and the 53px manages to appear only once, but support for subgrid is minimal.

Related

how to place multiple items in a grid column cell using tailwind?

I have a design where I have 3 items. 2 items should be placed vertically and 1 item has to be in it's own cell. So, 2 items should be placed in 1 cell vertically and 1 item takes it's own whole cell. To demonstrate, below is the image
How can I achieve this design using tailwind?
You can make such layout using grid - separate your layout on three columns (sidebar + main content spans on two columns) and 2 rows like #ChenBr did
<div class="border-2 grid grid-cols-3 grid-rows-2">
<div class="border-2 col-span-1">1</div>
<div class="border-2 col-span-2 row-span-2">2</div>
<div class="border-2 col-span-1">3</div>
<div>
However grid-rows-2 will be compiled as
.grid-rows-2 {
grid-template-rows: repeat(2, minmax(0, 1fr));
}
1fr for both rows means 2 rows will be sized equally. So I would recommend to change this class into grid-rows-[min-content_1fr] - that mean first row will take place base on its minimum content
min-content - is a keyword representing the largest minimal content contribution of the grid items occupying the grid track.
and the second one will take the rest - but it's up to your application
Basic example
<div class="grid grid-cols-3 grid-rows-[min-content_1fr]">
<div>1</div>
<div class="col-span-2 row-span-2">2</div>
<div>3</div>
<div>
DEMO
You can achieve this setup using grid/flex. Using one or the other depends on your content.
Grid:
Create a three-by-two grid using grid-cols-3 and grid-rows-2 on the grid's container. Then, set each container's span to fit your structure (using col-span-n row-span-n).
Read about grid-cols here and about grid-row here.
<div class="border-2 grid grid-cols-3 grid-rows-2">
<div class="border-2 col-span-1">1</div>
<div class="border-2 col-span-2 row-span-2">2</div>
<div class="border-2 col-span-1">3</div>
<div>
Tailwind-play
Flex:
We are going to have two containers. The main container will wrap all the elements (including the second container), and the inner container will wrap your first two elements. Each of those containers will have a flex utility applied to it.
Then, we will apply flex-col on the second container. This way, the container will place its children on top of each other, just like the first column of your image.
The first container's default flex-direction is flex-row which is why the inner container and the third element will be positioned next to each other, just like a row.
To give the structure a proportion similar to your image, we can set the inner container's width to 30% (w-[30%]), and the third element to 70% (w-[70%]).
Read about flex-direction here.
<div class="flex border-2">
<div class="flex w-[30%] flex-col">
<div class="border-2">1</div>
<div class="border-2">2</div>
</div>
<div class="w-[70%] border-2">3</div>
<div></div>
</div>
Tailwind-play

Inserting component on click between grid rows

I have a grid of items and when I click on one of them I want to show another component that takes all the width on the row under the clicked item.
Here is a picture of what I want to achieve
I have a button-list-component which contain a button-component that display my items with an ngFor.
When I click on an item the size-selection-component is shown with a ngIf.
My problem is that if I have the size-selection-component in the button-list-component, it append at the end of the grid, and if I have this new component in the button-component then it only takes the width of the column containing the clicked item.
If I put it in position absolute I can make it the width of the container but then the following items won't go down.
Here is a piece of my code
button-list
<div class="wrapper">
<div class="container">
<app-button *ngFor="let button of buttons;" [button]="button" (buttonClicked)="onButtonClicked($event)">
</app-button>
</div>
</div>
.container {
position: relative;
display: grid;
grid-template-columns: repeat(3, minmax(250rem, 1fr));
grid-gap: 10rem;
place-items: start center;
overflow-x: hidden;
overflow-y: auto;
margin: 10rem;
}
button
<div class="product">
<div class="product-col">
<h2 class="product_title" (click)="onButtonClicked()">{{button.Caption}}</h2>
<img class="product_img" [src]="picture" alt="" (click)="onButtonClicked()">
<span class="product_price" *ngIf="button.Price && button.Price != '0'">{{button.Price / 100 | currency}}</span>
</div>
</div>
<app-size-selection-button-list *ngIf="isSizeSelectionOpen"></app-size-selection-button-list>
How would it be possible to achieve that ? Maybe there is a solution in CSS or maybe another way to insert my component in the grid of items that would work.
Thanks
You don't have to append the div, you can create it and hide it, when user hover over the item div, you show it and set its child tag's innerHTML to whatever you need, like this
<body>
<p onmouseover="show();"></p>AA</p>
<div style="width:100%">
<div style="width:33%">
<p>Name</p>
</div>
<div style="width:33%">
<p>Name</p>
</div>
<div style="width:33%">
<p>Name</p>
</div>
</div>
<div id="blah" style="display:none">
<!-- whatever here -->
</div>
<script>
function show() {
var b=document.getElementById("blah");
b.style.display="block";
// Change some innerHTML of elements inside the blah div here
}
</script>

what tags are allowed as grid elements

this is a standard grid concept:
.wrap{
display:grid;
grid-template-columns: 1fr 1fr 1fr;
}
<div class='wrap'>
<div class='el'>lorem</div>
<div class='el'>ipsum</div>
<div class='el'>dolor</div>
</div>
I tried this:
<div class='wrap'>
<img class='el' src='...' alt='img'>
<img class='el' src='...' alt='img'>
<img class='el' src='...' alt='img'>
</div>
And seems it works - images as grid elements
So my question is - what else can I use as grid elements - inputs, forms, video...
I suppose there are some restrictions but can't find any specification regarding this.
Never rendered svg elements cannot be used as grid items for sure.
Other descendants of <svg> elements also probably can't be used, though I can't find any spec on those.
For HTML elements, pretty much anything works as a grid item if you force it to generate a CSS box.

Scroll only one part of horizontal row keeping the other fixed

html
<div class="xxx">
<div class="xyz" ng-repeat="item in formList">
<div ng-show="formList.indexOf(app)!= -1" class="added-item">
<img class="col-md-6 added-item-icon" ng-src="app.iconFile"/>
</div>
</div>
<div class="abc" ng-hide="formList.length>20">
<button class="btn" ng-click="addItem()">
Add<i class="glyphicon glyphicon-plus"></i>
</button>
</div>
</div>
css
.xxx {
width:500px;
height: 80px;
}
.added-item-icon, .abc {
width: 50px;
height: 50px;
}
I'm not good in css, and have only very basic knowledge
I am trying to add some list of items in a horizontal tab of height 80 and width 500 pixels, also an add app button too
As per the code, the add app button disappear when we add the 20th app
what I need to do is, lets say the xxx div(horizontal div) can have 5 items, after which overflow occurs
I want to set the overflow horizontal, not vertical
also at that stage(when 5 items are added), I want to fix the add app button at the very right of the division xxx, and the scroll due to overflow should not affect that button, it should be fixed there
we doesn't need to care more about the size of the item icons or add button,
Please help
For this you'll want to look into using flexbox. To get this working, all you really need to do is add display: flex; flex-direction: column to your container, and then overflow-y: auto to the section you want to scroll.
Heres a Plunker demonstrating it.

Bootstrap 3 Grid - hide/show columns

I'm using the Bootstrap 3 grid to hide/show nav bar content based on whether or not the user is using an extra small device.
I'm using .hidden-xs and .visible-xs classes. These classes appropriately hide/show the content, but I'm running into two problems:
(1) Hiding the content also shrinks the column spacing by .col-xs-5 because the div is hidden. I tried adding .visible-xs to a subsequent div and using .col-xs-5 to make up the empty space. This works, but only if I place content inside the divs. I just want the columns to be spaced out.
(2) On XS view size, the final item on the Nav bar "Nav" jumps to the next row. I have only accounted for 12 total columns.
See this JSFiddle. I'm trying to nly show "Welcome" on large view and show nothing on XS view.
I here's an idea, you can try instead of adding content. This CSS trick uses :before and :after CSS pseudo-classes.
.no_content {
display: block;
content: "";
width: 151px;
height: 35px;
background: transparent url(tape.png) 0 0 no-repeat;
}
<div class="no_content"></div>
I would look at the grid system further. I believe there is an offset that you can use to offset the div like this:
<div class="row">
<div class="col-xs-5 col-xs-offset-5></div>
<div class="col-xs-2></div>
</div>
Use the pull-right bootstrap class instead of trying to make empty div's fill in the space.
Completely remove the div you added in item (1) to "make up the space". On the div containing "Nav" set the class as pull-right col-xs-1. So the code from your JSFiddle becomes:
<div class="container">
<div class="row" id="header">
<div class="col-xs-5" id="brand-wrapper">
<div class="brand">Brand</div>
</div>
<!-- Hidden on XS Devices -->
<div class="hidden-xs col-xs-5">
<p>
Welcome
</p>
</div>
<!-- Nav -->
<div class="pull-right col-xs-1" id="toggle-wrapper">
<p>Nav</p>
</div>
</div>
</div>

Resources