Search code examples
tailwind-css

How can I push an element to the bottom of a div in tailwind? Should be simple, but just can't get it to work


I have a layout in tailwind which is pretty typical: a number of 'cards' which are placed into a grid container. Each card has a photo and some other text details with a button at the bottom of the card.

All I want to do is push the button to the bottom of the card. The code is below and there is also a link to play.tailwind.

<div class="grid sm:block grid-cols-5 sm:grid-cols-1 col-span-12 sm:col-span-6 md:col-span-4 lg:col-span-3 p-4">
  <div class="flex sm:h-[17em] mr-4 sm:mr-0 sm:mb-4 col-span-2 sm:col-span-1">
    <img class="grow object-cover" :src=''>
  </div>
  <div class="flex flex-col col-span-3 sm:col-span-1">
    <p class="mb-3">
      text
    </p>
    <p class="mb-3">
      more text
    </p>
    <div class="flex flex-wrap -mx-1 mb-3">
      some more text
    </div>
    <p class="mb-4 flex-1">
      even more
    </p>
    <button>
      the problem button
    </button>
  </div>
</div>

play.tailwind example

To me, it seems like <p class="mb-4 flex-1"> should take care of everything. But maybe it can't because its container won't allow it to grow? If I try to assign a h-full to its container, it extends past the card's container which is unexpected.

I've done this sort of thing before without thinking much about it. When I first encountered this problem, I went back and rebuilt the entire structure. After looking through the official docs and trying a number of methods using grids and flex, I'm even more confused. I just can't get it to work. Any ideas?


Solution

  • Your issue is that the <div class="flex flex-col col-span-3 sm:col-span-1"> element is only as high as its content. This means there is no empty space for the flex-grow: 1 part of flex-1 to grow into:

    Parent height does not take up the full height of the available empty space

    Consider adjusting the CSS so this element extends to the bottom of the content box of its own parent. Consider the following few methods of many:

    Grid

    Have the parent stay as a grid layout beyond the sm: breakpoint. Have two explicit grid row tracks, one that is the height of the image and another that is 1fr to fill the remaining vertical space. This then lets the aforementioned <div> expand fully, thus letting the <p> element expand fully:

    <script src="https://cdn.tailwindcss.com/3.3.5"></script>
    
    <div class="bg-slate-400 py-24">
      <div class="container mx-auto grid grid-cols-12 gap-8 px-4">
        <div class="col-span-12 grid grid-cols-5 border p-4 sm:col-span-6 sm:grid-cols-1 sm:grid-rows-[max-content_1fr] md:col-span-4 lg:col-span-3">
          <div class="col-span-2 mr-4 flex sm:col-span-1 sm:mb-4 sm:mr-0 sm:h-[17em]">
            <img class="grow border object-cover" />
          </div>
          <div class="col-span-3 flex flex-col sm:col-span-1">
            <p class="mb-3 font-serif text-2xl">First Last</p>
            <p class="mb-3 text-sm font-medium uppercase tracking-widest">City, Country</p>
            <div class="-mx-1 mb-3 flex flex-wrap text-xs font-medium uppercase tracking-widest">
              <div class="m-1 inline w-min break-words rounded bg-slate-800 px-3 py-1 text-slate-400">Something</div>
            </div>
            <p class="mb-4 flex-1">Bio text here: Fusce in lacus lobortis, luctus eros nec, maximus nisl.</p>
            <button class="border">The problem</button>
          </div>
        </div>
        <div class="col-span-12 grid grid-cols-5 border p-4 sm:col-span-6 sm:grid-cols-1 sm:grid-rows-[max-content_1fr] md:col-span-4 lg:col-span-3">
          <div class="col-span-2 mr-4 flex sm:col-span-1 sm:mb-4 sm:mr-0 sm:h-[17em]">
            <img class="grow border object-cover" />
          </div>
          <div class="col-span-3 flex flex-col sm:col-span-1">
            <p class="mb-3 font-serif text-2xl">First Last</p>
            <p class="mb-3 text-sm font-medium uppercase tracking-widest">City, Country</p>
            <div class="-mx-1 mb-3 flex flex-wrap text-xs font-medium uppercase tracking-widest">
              <div class="m-1 inline w-min break-words rounded bg-slate-800 px-3 py-1 text-slate-400">Something</div>
            </div>
            <p class="mb-4 flex-1">Bio text here: Nam non lorem ac ex hendrerit semper.</p>
            <button class="border">Also the problem</button>
          </div>
        </div>
        <div class="col-span-12 grid grid-cols-5 border p-4 sm:col-span-6 sm:grid-cols-1 sm:grid-rows-[max-content_1fr] md:col-span-4 lg:col-span-3">
          <div class="col-span-2 mr-4 flex sm:col-span-1 sm:mb-4 sm:mr-0 sm:h-[17em]">
            <img class="grow border object-cover" />
          </div>
          <div class="col-span-3 flex flex-col sm:col-span-1">
            <p class="mb-3 font-serif text-2xl">First Last</p>
            <p class="mb-3 text-sm font-medium uppercase tracking-widest">City, Country</p>
            <div class="-mx-1 mb-3 flex flex-wrap text-xs font-medium uppercase tracking-widest">
              <div class="m-1 inline w-min break-words rounded bg-slate-800 px-3 py-1 text-slate-400">Something</div>
            </div>
            <p class="mb-4 flex-1">Bio text here: Morbi egestas massa vel nunc scelerisque viverra. Aliquam a urna vel quam rhoncus laoreet. Cras volutpat velit sed arcu varius iaculis. Nam cursus eros in porttitor dictum.</p>
            <button class="border">A button</button>
          </div>
        </div>
      </div>
    </div>

    Vertical Flex

    Have the parent as a vertical flex layout beyond the sm: breakpoint. Have the <div> expand fully by applying flex-grow: 1 via the grow class, thus letting the <p> element expand fully:

    <script src="https://cdn.tailwindcss.com/3.3.5"></script>
    
    <div class="bg-slate-400 py-24">
      <div class="container mx-auto grid grid-cols-12 gap-8 px-4">
        <div class="col-span-12 grid grid-cols-5 border p-4 sm:col-span-6 sm:flex sm:flex-col md:col-span-4 lg:col-span-3">
          <div class="col-span-2 mr-4 flex sm:col-span-1 sm:mb-4 sm:mr-0 sm:h-[17em]">
            <img class="grow border object-cover" />
          </div>
          <div class="col-span-3 flex grow flex-col sm:col-span-1">
            <p class="mb-3 font-serif text-2xl">First Last</p>
            <p class="mb-3 text-sm font-medium uppercase tracking-widest">City, Country</p>
            <div class="-mx-1 mb-3 flex flex-wrap text-xs font-medium uppercase tracking-widest">
              <div class="m-1 inline w-min break-words rounded bg-slate-800 px-3 py-1 text-slate-400">Something</div>
            </div>
            <p class="mb-4 flex-1">Bio text here: Fusce in lacus lobortis, luctus eros nec, maximus nisl.</p>
            <button class="border">The problem</button>
          </div>
        </div>
        <div class="col-span-12 grid grid-cols-5 border p-4 sm:col-span-6 sm:flex sm:flex-col md:col-span-4 lg:col-span-3">
          <div class="col-span-2 mr-4 flex sm:col-span-1 sm:mb-4 sm:mr-0 sm:h-[17em]">
            <img class="grow border object-cover" />
          </div>
          <div class="col-span-3 flex grow flex-col sm:col-span-1">
            <p class="mb-3 font-serif text-2xl">First Last</p>
            <p class="mb-3 text-sm font-medium uppercase tracking-widest">City, Country</p>
            <div class="-mx-1 mb-3 flex flex-wrap text-xs font-medium uppercase tracking-widest">
              <div class="m-1 inline w-min break-words rounded bg-slate-800 px-3 py-1 text-slate-400">Something</div>
            </div>
            <p class="mb-4 flex-1">Bio text here: Nam non lorem ac ex hendrerit semper.</p>
            <button class="border">Also the problem</button>
          </div>
        </div>
        <div class="col-span-12 grid grid-cols-5 border p-4 sm:col-span-6 sm:flex sm:flex-col md:col-span-4 lg:col-span-3">
          <div class="col-span-2 mr-4 flex sm:col-span-1 sm:mb-4 sm:mr-0 sm:h-[17em]">
            <img class="grow border object-cover" />
          </div>
          <div class="col-span-3 flex grow flex-col sm:col-span-1">
            <p class="mb-3 font-serif text-2xl">First Last</p>
            <p class="mb-3 text-sm font-medium uppercase tracking-widest">City, Country</p>
            <div class="-mx-1 mb-3 flex flex-wrap text-xs font-medium uppercase tracking-widest">
              <div class="m-1 inline w-min break-words rounded bg-slate-800 px-3 py-1 text-slate-400">Something</div>
            </div>
            <p class="mb-4 flex-1">Bio text here: Morbi egestas massa vel nunc scelerisque viverra. Aliquam a urna vel quam rhoncus laoreet. Cras volutpat velit sed arcu varius iaculis. Nam cursus eros in porttitor dictum.</p>
            <button class="border">A button</button>
          </div>
        </div>
      </div>
    </div>

    Height Calculation

    Have the <div> fill the remaining space of its parent by setting its height appropriately. We wouldn't apply height: 100% (h-full) as you have found out, it would overflow. This is because the height would be the height of the container, but we have other elements alongside – the <img> container. What we can do instead is since the <img> container has a set height, we can calculate the height that the <div> should be as follows:

    height = 100% - [Height of image container] - [Vertical margin of image container]
           = 100% - 17em - theme(spacing.5)
    
    height: calc(100% - 17em - theme(spacing.5))
    
    <div class="… h-[calc(100%-17em-theme(spacing.5))]">
    

    <script src="https://cdn.tailwindcss.com/3.3.5"></script>
    
    <div class="bg-slate-400 py-24">
      <div class="container mx-auto grid grid-cols-12 gap-8 px-4">
        <div class="col-span-12 grid grid-cols-5 border p-4 sm:col-span-6 sm:block md:col-span-4 lg:col-span-3">
          <div class="col-span-2 mr-4 flex sm:col-span-1 sm:mb-4 sm:mr-0 sm:h-[17em]">
            <img class="grow border object-cover" />
          </div>
          <div class="col-span-3 flex flex-col sm:col-span-1 sm:h-[calc(100%-17em-theme(spacing.4))]">
            <p class="mb-3 font-serif text-2xl">First Last</p>
            <p class="mb-3 text-sm font-medium uppercase tracking-widest">City, Country</p>
            <div class="-mx-1 mb-3 flex flex-wrap text-xs font-medium uppercase tracking-widest">
              <div class="m-1 inline w-min break-words rounded bg-slate-800 px-3 py-1 text-slate-400">Something</div>
            </div>
            <p class="mb-4 flex-1">Bio text here: Fusce in lacus lobortis, luctus eros nec, maximus nisl.</p>
            <button class="border">The problem</button>
          </div>
        </div>
        <div class="col-span-12 grid grid-cols-5 border p-4 sm:col-span-6 sm:block md:col-span-4 lg:col-span-3">
          <div class="col-span-2 mr-4 flex sm:col-span-1 sm:mb-4 sm:mr-0 sm:h-[17em]">
            <img class="grow border object-cover" />
          </div>
          <div class="col-span-3 flex flex-col sm:col-span-1 sm:h-[calc(100%-17em-theme(spacing.4))]">
            <p class="mb-3 font-serif text-2xl">First Last</p>
            <p class="mb-3 text-sm font-medium uppercase tracking-widest">City, Country</p>
            <div class="-mx-1 mb-3 flex flex-wrap text-xs font-medium uppercase tracking-widest">
              <div class="m-1 inline w-min break-words rounded bg-slate-800 px-3 py-1 text-slate-400">Something</div>
            </div>
            <p class="mb-4 flex-1">Bio text here: Nam non lorem ac ex hendrerit semper.</p>
            <button class="border">Also the problem</button>
          </div>
        </div>
        <div class="col-span-12 grid grid-cols-5 border p-4 sm:col-span-6 sm:block md:col-span-4 lg:col-span-3">
          <div class="col-span-2 mr-4 flex sm:col-span-1 sm:mb-4 sm:mr-0 sm:h-[17em]">
            <img class="grow border object-cover" />
          </div>
          <div class="col-span-3 flex flex-col sm:col-span-1 sm:h-[calc(100%-17em-theme(spacing.4))]">
            <p class="mb-3 font-serif text-2xl">First Last</p>
            <p class="mb-3 text-sm font-medium uppercase tracking-widest">City, Country</p>
            <div class="-mx-1 mb-3 flex flex-wrap text-xs font-medium uppercase tracking-widest">
              <div class="m-1 inline w-min break-words rounded bg-slate-800 px-3 py-1 text-slate-400">Something</div>
            </div>
            <p class="mb-4 flex-1">Bio text here: Morbi egestas massa vel nunc scelerisque viverra. Aliquam a urna vel quam rhoncus laoreet. Cras volutpat velit sed arcu varius iaculis. Nam cursus eros in porttitor dictum.</p>
            <button class="border">A button</button>
          </div>
        </div>
      </div>
    </div>