Home > Back-end >  Decrease padding size as parent element getting smaller
Decrease padding size as parent element getting smaller

Time:01-11

I have a grid that draws squares in cells. It has number of rows and number of columns, then it draw the grid cells and check if in each cell there should be a square or not (according to an array) and draws a square if needed. The HTML end result looks something like this: (lets say I have 1 row and 3 columns and only 2 cells should have squars)

.row {
  display: flex;
  flex-wrap: wrap;
  flex: 10000 1 0%;
}

.column {
  display: flex;
  flex-wrap: wrap;
  max-width: 100px;
  min-width: 10px;
  padding: 4px;
  border: 1px solid grey;
}

.square {
  background-color: red;
  width: 100%;
  aspect-ratio: 1/1;
  border-radius: 5px;
}
<div >
    <div >
        <div ></div>
    </div>
    <div >
        <div ></div>
    </div>
    <div ></div>
</div>

The rows take the full width of the screen and the size of the columns should be identical between all of the columns and changing by the number of columns on the screen (For example if I have 5 columns they should all be with a width of 100px, but if I have 1000 columns they should all be with a width of 10px).

My problem is that after a certain break point in the column size the padding and border radius seems weird and I want to change their values when I hit that break point. I can't use @container queries as there are still not fully supported.

If it help I'm using vue 2. but I think a CSS solution will be better in this case.

CodePudding user response:

I am Sahil Atahar.

if you want to increase or decrease size of padding you can give padding size in percent (%) that depends on parent element.

CodePudding user response:

Trying to address the issue described:

My problem is that after a certain break point in the column size the padding and border radius seems weird and I want to change their values when I hit that break point. I can't use @container queries as there are still not fully supported.

I crafted a little demo that helped me better explore the conditions bringing to such a scenario.

Obtaining border: collapse equivalent on flexbox items

The .row element remains a flexbox container but its flex items instead of having their border set, they are styled with their outline set.

The outline doesn't occupy space and it's expected to "collapse" when colliding with the outline produced by another element.

So to make it sure the layout wasn't affected by styling oddities, in the attempt to show off the borders of the flex items, this demo just relies on 2 key aspects to render those borders:

  • Setting the gap between the flex items
  • Setting the outline size expected to cover the gap left between elements
.row {
  gap: var(--col-gap);
}
.column {
  outline: var(--col-gap) solid gray;
}

Using ::after for adding content to an element

Plus the red dot is applied as an ::after pseudo element with position:absolute, again to make sure that nothing affected the grid layout:

.column.square::after {
  position: absolute;
  content: '';
  background-color: red;
  
  width: 50%;
  aspect-ratio: 1/1;
  border-radius: 100%;
  
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); 
}

The dashboard - exploring the options

Starting from there I added a "dashboard" with position: fixed that remains on top of the page and lets you control:

  • column width (px): here you set the width changing the cols per row according to the available container space
  • columns per row: here you set the cols per row changing their width according to the available container space width
  • gap between cells (px): the gap between cells on the grid
  • toggle red dots visibility: will show/hide the red dots proving again that display: none; doesn't change the grid layout that it's depending exclusively by the .column element size set through the custom variable --col-width
  • toggle counter visibility: will show/hide the counter on top of each flex item

Conclusions so far:

Despite the efforts to minimize any interfence and taking all the steps needed to correctly setup a grid layout depending only on the fixed size of its cells, there are still some rendering issue with sometimes the occurrence of regular mismatching patterns on the border size for some lines. I should say that I only experience the problem on my laptop display and not on my desktop monitor so that's another factor.

I tried with different parameters on my demo and playing with the numbers, considering also the gap. A good and safe layout can be found minimizing potential problems (also raising the border size for example).

I couldn't get further than this using the flex layout.

const container = document.getElementById('container');

//draws the board
emptyElementAndFillWithColumns(container, 100);
//sets some columns randomly as .square
addRandomSquares(container);

//initializes the dashboard with the value coming from the css custom props
let columnsGap = parseInt(getCssCustomProp('col-gap'));
let columnsWidth = parseInt(getCssCustomProp('col-width'));
document.getElementById('gap').value = columnsGap;
document.getElementById('width').value = columnsWidth;
document.getElementById('width').dispatchEvent(new Event('change'));
document.getElementById('cols').value = Math.trunc(container.offsetWidth / (columnsWidth columnsGap));

//input#width change event handler
document.getElementById('width')
  .addEventListener('change', event => {
    const width = parseInt(event.target.value);
    const newCols = Math.trunc(container.offsetWidth / (width columnsGap));
    setCssCustomProp(container, 'col-width', `${width}px`);
    document.getElementById('cols').value = newCols;
  });

//input#cols change event handler
document.getElementById('cols')
  .addEventListener('change', event => {
    const cols = parseInt(event.target.value);
    const newWidth = Math.trunc(container.offsetWidth / cols) - columnsGap;
    setCssCustomProp(container, 'col-width', `${newWidth}px`);
    document.getElementById('width').value = newWidth;
  });
  
//input#gap change event handler
document.getElementById('gap')
  .addEventListener('change', event => {
    const gap = parseInt(event.target.value);
    setCssCustomProp(container, 'col-gap', `${gap}px`);
    columnsGap = gap;
  });
  
//input#toggle-dots change event handler
document.getElementById('toggle-dots')
  .addEventListener('change', event => {
    container.classList.toggle('hide-dots');
  });
  
//input#toggle-counters change event handler
document.getElementById('toggle-counters')
  .addEventListener('change', event => {
    container.classList.toggle('hide-counters');
  });

//sets the --propName custom property at the style of target
function setCssCustomProp(target, propName, value){
  target.style.setProperty(`--${propName}`, `${value}`);
}

//gets the --propName custom property value from the rule set on :root
function getCssCustomProp(propName){
  const propValue =
  getComputedStyle(document.documentElement).getPropertyValue(`--${propName}`);
  return propValue;
}

//resets the container and appends a count number of columns
function emptyElementAndFillWithColumns(target, count){
  for (i = 0; i <= count; i  ) {
    const column = document.createElement('div');
    column.classList.add('column');
    target.append(column);
  }
}

//adds the square class to random .column elements in target
function addRandomSquares(target){
  target.querySelectorAll('.column').forEach(column => {
    if (Math.random() >= 0.5)
      column.classList.add('square');
  })
}
:root {
  --col-width: 100px;
  --col-gap: 1px;
}

*,
*::after,
*::before {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: sans-serif;
}

.row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--col-gap);
  counter-reset: itemnr;
}

.column {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  width: var(--col-width);
  height: var(--col-width);
  padding: 4px;
  outline: var(--col-gap) solid gray;
}

.column.square::after {
  position: absolute;
  content: '';
  background-color: red;
  
  width: 50%;
  aspect-ratio: 1/1;
  border-radius: 100%;
  
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); 
}

.dashboard {
  position: fixed;
  right: 1rem;
  top: 2rem;
  border: solid darkgray;
  padding: 1em;
  z-index: 100;
  background: gray;
  color: white;
  font-weight: 600;
  font-size: 1.2rem;
  opacity: .9;
}

.dashboard > *{
  display: grid;
  grid-template-columns: 1fr auto;
  width: 100%;
  gap: 1em;
}

.dashboard label{
}

.dashboard input[type="number"] {
  width: 5em;
  cursor: pointer;
}

.dashboard input[type="checkbox"] {
  width: 1rem;
  line-height: 1rem;
  cursor: pointer;
}

#container.hide-dots .square::after{
  display: none;
}

#container.hide-counters .column::before{
  display: none;
}

small{
  grid-column: 1 / -1;
  font-size:.8rem;
  text-align: center;
  width: 100%;
  margin-bottom: 1rem;
}

.column::before{
  position: absolute;
  counter-increment: itemnr; 
  content: counter(itemnr);
  font-size: .8rem;
  z-index: 10;
  font-weight: 600;
}
<div id="container" >
  <div >
  </div>
  <div ></div>
</div>

<div >
  <div>
    <label for="width">column width (px):</label>
    <input
      id="width" type="number" max="100" min="10">
  </div>
  <div>
    <label for="cols">columns per row:</label>
    <input
      id="cols" type="number" max="50" min="1">
  </div>
  <div>
    <label for="gap">gap between cells (px):</label>
    <input
      id="gap" type="number" max="10" min="0">
  </div>
  <div style="margin-top: 1rem;">
    <label for="toggle-dots">toggle red dots visibility:</label>
    <input id="toggle-dots" type="checkbox" checked>
  </div>
  <div>
    <label for="toggle-counters">toggle counter visibility:</label>
    <input id="toggle-counters" type="checkbox" checked>
  </div>
</div>

  • Related