Home > Back-end >  Flexbox child shrinks beyond set minimum width
Flexbox child shrinks beyond set minimum width

Time:06-23

I'm having a serious CSS challenge on a small project I'm building:

I have a <main> element which is set as flexbox of row. inside are 3 children:

:root {
  --clr-light-text: #f2f2f2;
  --clr-dark-text: #48484a;
  --shadow-default: 0px 2px 8px rgba(0, 0, 0, 0.2);
  --vid-container-h: 0px;
  color: var(--clr-light-text);
  font-family: 'Poppins', sans-serif;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  list-style: none;
  text-decoration: none;
}

h1,
h2,
h3,
h4 {
  font-weight: 400;
}

body {
  background-color: var(--clr-dark-text);
  text-align: center;
  overflow-x: hidden;
  scroll-behavior: smooth;
}

.glass {
  background-image: linear-gradient( 135deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0));
  backdrop-filter: blur(5px);
  border: 1px solid rgba(255, 255, 255, 0.15);
  box-shadow: var(--shadow-default);
  border-radius: 0.5rem;
}

main {
  display: flex;
  justify-content: center;
  padding: 0 1rem;
  gap: 2rem;
}

.main-container {
  background-color: hsl(0, 0%, 75%);
  padding-bottom: 10rem;
  position: relative;
}

.weather-box {
  width: clamp(13.5rem, 18%, 20rem);
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  padding: 0 1em 1em 1em;
}

#weather-icon {
  margin: -15% -10%;
}

.weather-details {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

#forecast,
#temp,
#humidity {
  display: flex;
  flex-direction: column;
  align-items: center;
}

#temp {
  margin-bottom: 1em;
  font-weight: 200;
}

#temp-num {
  font-size: 3em;
}

#humid {
  font-size: 1.5em;
}

#humid-value {
  font-size: 1.5em;
  font-weight: 200;
}

#humid-value img {
  max-width: 1em;
}

#forecast-desc {
  font-size: 2.5em;
  font-weight: 400;
}

.playlist-box {
  width: clamp(13.5rem, 18%, 20rem);
  display: flex;
  align-items: center;
  flex-direction: column;
  padding: 1rem 0.5em;
  flex-shrink: 0;
}

.playlist-box h3::after {
  content: '';
  width: 70%;
  height: 1px;
  background-color: rgba(255, 255, 255, 0.3);
  border-radius: 100vmax;
  display: block;
  margin: 1em auto;
}

#playlist {
  display: grid;
  width: 100%;
  padding: 1em;
  overflow-y: scroll;
  scroll-behavior: smooth;
}

#playlist li {
  margin-bottom: 1rem;
  width: 100%;
  padding: 1rem;
  border: 1px solid rgba(255, 255, 255, 0);
}

#playlist li:hover,
#playlist li:focus {
  background-image: linear-gradient( 135deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0));
  border: 1px solid rgba(255, 255, 255, 0.15);
  box-shadow: var(--shadow-default);
  border-radius: 0.5rem;
}

.song-title {
  margin-bottom: 0.5em;
}

.vid-thumb {
  width: 100%;
  /* object-position: center;
  object-fit: cover; */
}

.video-container {
  align-self: flex-start;
  padding: 1em;
}

#song-frame {
  position: relative;
  overflow: hidden;
  width: 100%;
  padding-top: 56.25%;
}

#song-frame iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
<div >
  <main>
    <aside >
      <div id="forecast">
        <img id="weather-icon" src="http://openweathermap.org/img/wn/[email protected]" alt="Weather Icon" />
        <span id="forecast-desc">(--)</span>
      </div>
      <div >
        <div id="temp">
          <span id="temp-num">0&deg;c</span>
          <span id="feels-like">feels like 0&deg;c</span>
        </div>
        <div id="humidity">
          <span id="humid">Humidity</span>
          <div id="humid-value">
            <span id="humid-num">0%</span>
          </div>
        </div>
      </div>
    </aside>

    <div >
      <div id="song-frame">
        <iframe src="https://www.youtube.com/embed/oG08ukJPtR8" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" width="1024" height="576" frameborder="0"></iframe>
      </div>
    </div>
    <aside >
      <h3>Browse Playlist:</h3>
      <ul id="playlist">
        <li>
          <h4>Song Title</h4>
          <img  src="https://i.ytimg.com/vi/ru0K8uYEZWw/hqdefault.jpg" alt="" />
        </li>
        <li>
          <h4>Song Title</h4>
          <img  src="https://i.ytimg.com/vi/pkCyfBibIbI/hqdefault.jpg" alt="" />
        </li>
      </ul>
    </aside>
  </main>
</div>

I applied to both <aside> elements to have a responsive width with the following width: clamp(13.5rem, 18%, 20rem). The div in the center uses the rest of the available width of the viewport. Generally, the layout kinda works.

The weather-container's clamp works just fine. The playlist-container though is able to shrink to less than 13.5rem (216px) and in some screen sizes I'm left with uneven containers in the sides.

The interesting part is that problem is somehow connected to the <img> thumbnails. The set width for them is 100%. If I cancel it out, the container behaves correctly but the thumbnails are cut off.

  • setting a fixed width value doesn't work.
  • setting a min-width to the element doesn't work.
  • setting flex-shrink: 0; to the element doesn't work.
  • messing with flex-basis also didn't work for me.
  • changing the <img> to a <div> with background-image instead produces the same result.

Would love to get over this problem, thank you.

Edit: I've produced a CodePen which recreates the problem: https://codepen.io/xandertem/pen/XWZLaVR

Try going to responsive mode and see the right section shrinking around <560px.

CodePudding user response:

For reasons I don't understand clamp in the width setting of flex just does not seem to work.

Also to automatically have the two asides with the height of the middle item you could use grid.

To get round what seems to be the clamp problem this snippet separates out the ranges by using min and max width media queries [when 18% is 13.5rem the overall width is 75rem and so on).

* {
  box-sizing: border-box;
}

main {
  display: grid;
  grid-template-columns: 18% 1fr 18%;
  width: 100vw;
}

@media screen and (max-width: 75rem) {
  main {
    grid-template-columns: 13.5rem 1fr 13.5rem;
  }
}

@media screen and (min-width: 111.111rem) {
  main {
    grid-template-columns: 20rem 1fr 20rem;
  }
}

main {
  padding: 0 1rem;
  gap: 2rem;
}

.weather-container {
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  padding: 0 1em 1em 1em;
}

.video-container {
  padding: 1em;
}

.playlist-container {
  display: flex;
  align-items: center;
  flex-direction: column;
  padding: 1rem 0.5em;
}

.vid-thumb {
  width: 100%;
  /* object-position: center;
  object-fit: cover; */
}
<main>
  <div >
    ...divs...
  </div>
  <div >
    <div>
      <iframe>...</iframe>
    </div>
  </div>
  <div >
    <h3>Browse Playlist:</h3>
    <ul>
      <li>
        <h4>Song Title</h4>
        <img  src="https://i.ytimg.com/vi/example.jpg" alt="">
      </li>
      <li>etc...</li>
    </ul>
  </div>
</main>

CodePudding user response:

Adding flex-shrink: 0 to the aside (.playlist-box) solves the problem.

You should probably add the same rule to the other aside (.weather-box), even though you don't need it, just in case the type of content in that container ever changes. As you can see, images and videos make a difference.

  • Related