Search code examples
javascripthtmlcssvue.jsbootstrap-vue

Can I position a button at the bottom of a card without position: absolute;? (vue-bootstrap)


So I'm trying to create a simple card with just a background image and a button, with the buttons link being stretched over the entire card. The button looks awful not at the bottom though, but if I use an absolute position, it removes the stretched link.

enter image description here

<template>
    <div>
        <h2>College Management Home</h2>

        <b-card
            class="sCardHome m-3"
            header="Courses"
            overlay
            img-src="https://picsum.photos/325/200/?image=26"
            img-alt="Card Image"
        >
            <b-button class="stretched-link homebtn" :to="{ name: 'viewCourses'}" variant="primary">View Courses</b-button>
        </b-card>

        <b-card
            class="sCardHome m-3"
            header="Lecturers"
            overlay
            img-src="https://picsum.photos/325/200/?image=27"
            img-alt="Card Image"
        >
            <b-button class="homebtn stretched-link" :to="{ name: 'viewLecturers'}" variant="primary">View Lecturers</b-button>
        </b-card>

        <b-card
            class="sCardHome m-3"
            header="Enrolments"
            overlay
            img-src="https://picsum.photos/325/200/?image=30"
            img-alt="Card Image"
        >
            <b-button class="homebtn stretched-link" :to="{ name: 'viewEnrolments'}" variant="primary">View Enrolments</b-button>
        </b-card>

    </div>
</template>

<script>
export default {
    name: 'home',
    components: {}
}
</script>

<style>
.sCardHome {
    width: 100%;
    max-width: 20rem;
    float:left;
    text-align: center;
}
.homebtn {
    /* position: absolute; */
    bottom: 15px;
}
</style>

On a side note, is there a simple way I can have the cards margins stretch to fill the space, so the first card in a row is left aligned with the page & navbar title, and the last card in a row is right aligned with the logout button, so margins fill out the space in the middle so it all fits (in this instance, a margin left and right for the middle picture, can't be hard coded though as it needs to be responsive)? I tried the mx-auto class, on each cards and a div container, but neither worked at all.


Solution

  • You can do this pretty easily by utilizing flexbox.

    Bootstrap provides some utility classes. This includes display utilities like d-flex which applies display: flex to an element. We'll apply this card to out card body via the body-class prop on <b-card>.

    Then to get the button position, we can use a auto margin. Luckily for us Bootstrap provides spacing utilities for this. So here we can apply mt-auto (margin-top: auto) to push the button to the bottom. If we want to center the button horizontally we apply the mx-auto (margin-left: auto; margin-right: auto) class as well.

    There are other ways to position elements with flex, if you want to see some alternatives you can check out the flex utility page on the bootstrap docs.

    Example:

    new Vue({
      el: "#app"
    });
    <link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap@4.5.3/dist/css/bootstrap.min.css" />
    <script src="//unpkg.com/vue@2.6.12/dist/vue.min.js"></script>
    <script src="//unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.min.js"></script>
    
    
    <div id="app" class="p-4">
      <b-card-group>
        <b-card v-for="i in 2" class="m-3" header="Courses" overlay img-src="https://picsum.photos/325/200/?image=26" img-alt="Card Image" header-class="text-center" body-class="d-flex">
          <b-button class="stretched-link mt-auto mx-auto" variant="primary">
            View Courses
          </b-button>
        </b-card>
      </b-card-group>
    </div>