[SalesForce] SLDS lightning card margin issue

When lightning cards render, the first one seems to always be missaligned at the top no matter what. (this is obviously fixable with CSS).
I used dymamic rendering, standard lightning:Card component and SLDS card blueprints, all resulted in the same behavior.

dynamic lightning card:

component.cmp

<div class="slds-grid slds-wrap">
    {!v.body}
</div>

componentController.js

    doInit : function(cmp, evt, helper) {
        const featureCards = cmp.get('v.newFeatures');
     
        featureCards.forEach( function(element){
            helper.createComponent(cmp, evt, element);
        })
    },

componentHelper.js

    createComponent : function(cmp, evt, data) {
     $A.createComponent(
        "c:newFeatureCard",
        {
            "title": data.component.label,
            "cardBody": data.component.description
        },
        function(newCard, status, errorMessage){
            //Add the new button to the body array
            if (status === "SUCCESS") {
                var body = cmp.get("v.body");
                body.push(newCard);
                cmp.set("v.body", body);
            }
            else if (status === "INCOMPLETE") {
                console.log("No response from server or client is offline.")
                // Show offline error
            }
            else if (status === "ERROR") {
                console.log("Error: " + errorMessage);
                // Show error message
            }
        }
    );
},

lightning:card component:

component.cmp

    <div>Non Dynamic Cards</div>
<div class="slds-grid slds-wrap">
    <lightning:card class="feature-card slds-float_left slds-size--1-of-3">
        <aura:set attribute="title">
            <lightning:icon iconName="utility:connected_apps" size="small"/>
            asdasd
        </aura:set>
        <aura:set attribute="footer">
            <lightning:badge label="Tag1"/>
            <lightning:badge label="Tag2"/>
            <lightning:badge label="Tag3"/>
        </aura:set>
        Card Body (custom component)
    </lightning:card>
    <lightning:card class="feature-card slds-float_left slds-size--1-of-3">
        <aura:set attribute="title">
            <lightning:icon iconName="utility:connected_apps" size="small"/>
            asdasd
        </aura:set>
        <aura:set attribute="footer">
            <lightning:badge label="Tag1"/>
            <lightning:badge label="Tag2"/>
            <lightning:badge label="Tag3"/>
        </aura:set>
        Card Body (custom component)
    </lightning:card>
    <lightning:card class="feature-card slds-float_left slds-size--1-of-3">
        <aura:set attribute="title">
            <lightning:icon iconName="utility:connected_apps" size="small"/>
            asdasd
        </aura:set>
        <aura:set attribute="footer">
            <lightning:badge label="Tag1"/>
            <lightning:badge label="Tag2"/>
            <lightning:badge label="Tag3"/>
        </aura:set>
        Card Body (custom component)
    </lightning:card>
    <lightning:card class="feature-card slds-float_left slds-size--1-of-3">
        <aura:set attribute="title">
            <lightning:icon iconName="utility:connected_apps" size="small"/>
            asdasdasd
        </aura:set>
        <aura:set attribute="footer">
            <lightning:badge label="Tag1"/>
            <lightning:badge label="Tag2"/>
            <lightning:badge label="Tag3"/>
        </aura:set>
        Card Body (custom component)
    </lightning:card>
    <lightning:card class="feature-card slds-float_left slds-size--1-of-3">
        <aura:set attribute="title">
            <lightning:icon iconName="utility:connected_apps" size="small"/>
            asdsad
        </aura:set>
        <aura:set attribute="footer">
            <lightning:badge label="Tag1"/>
            <lightning:badge label="Tag2"/>
            <lightning:badge label="Tag3"/>
        </aura:set>
        Card Body (custom component)
    </lightning:card>
    <lightning:card class="feature-card slds-float_left slds-size--1-of-3">
        <aura:set attribute="title">
            <lightning:icon iconName="utility:connected_apps" size="small"/>
            asdasdsda
        </aura:set>
        <aura:set attribute="footer">
            <lightning:badge label="Tag1"/>
            <lightning:badge label="Tag2"/>
            <lightning:badge label="Tag3"/>
        </aura:set>
        Card Body (custom component)
    </lightning:card>
    
</div>

SLDS Card Blueprint:

component.cmp

   <div>SLDS BluePrint Cards</div>
<div class="slds-grid slds-wrap">
    <article class="slds-card feature-card slds-float_left slds-size--1-of-3">
        <div class="slds-card__header slds-grid">
            <header class="slds-media slds-media_center slds-has-flexi-truncate">
                <div class="slds-media__figure">
                    <span class="slds-icon_container slds-icon-standard-account" title="account">
                        
                        <span class="slds-assistive-text">account</span>
                    </span>
                </div>
                <div class="slds-media__body">
                    <h2 class="slds-card__header-title">
                        <a href="javascript:void(0);" class="slds-card__header-link slds-truncate" title="Accounts">
                            <span class="slds-text-heading_small">Accounts</span>
                        </a>
                    </h2>
                </div>
                <div class="slds-no-flex">
                    <button class="slds-button slds-button_neutral">New</button>
                </div>
            </header>
        </div>
        <div class="slds-card__body slds-card__body_inner">Anything can go in the Card Body</div>
        <footer class="slds-card__footer">
        </footer>
    </article>
    
    <article class="slds-card feature-card slds-float_left slds-size--1-of-3">
        <div class="slds-card__header slds-grid">
            <header class="slds-media slds-media_center slds-has-flexi-truncate">
                <div class="slds-media__figure">
                    <span class="slds-icon_container slds-icon-standard-account" title="account">
                        
                        <span class="slds-assistive-text">account</span>
                    </span>
                </div>
                <div class="slds-media__body">
                    <h2 class="slds-card__header-title">
                        <a href="javascript:void(0);" class="slds-card__header-link slds-truncate" title="Accounts">
                            <span class="slds-text-heading_small">Accounts</span>
                        </a>
                    </h2>
                </div>
                <div class="slds-no-flex">
                    <button class="slds-button slds-button_neutral">New</button>
                </div>
            </header>
        </div>
        <div class="slds-card__body slds-card__body_inner">Anything can go in the Card Body</div>
        <footer class="slds-card__footer">
        </footer>
    </article>
    <article class="slds-card feature-card slds-float_left slds-size--1-of-3">
        <div class="slds-card__header slds-grid">
            <header class="slds-media slds-media_center slds-has-flexi-truncate">
                <div class="slds-media__figure">
                    <span class="slds-icon_container slds-icon-standard-account" title="account">
                        
                        <span class="slds-assistive-text">account</span>
                    </span>
                </div>
                <div class="slds-media__body">
                    <h2 class="slds-card__header-title">
                        <a href="javascript:void(0);" class="slds-card__header-link slds-truncate" title="Accounts">
                            <span class="slds-text-heading_small">Accounts</span>
                        </a>
                    </h2>
                </div>
                <div class="slds-no-flex">
                    <button class="slds-button slds-button_neutral">New</button>
                </div>
            </header>
        </div>
        <div class="slds-card__body slds-card__body_inner">Anything can go in the Card Body</div>
        <footer class="slds-card__footer">
        </footer>
    </article>
    <article class="slds-card feature-card slds-float_left slds-size--1-of-3">
        <div class="slds-card__header slds-grid">
            <header class="slds-media slds-media_center slds-has-flexi-truncate">
                <div class="slds-media__figure">
                    <span class="slds-icon_container slds-icon-standard-account" title="account">
                        
                        <span class="slds-assistive-text">account</span>
                    </span>
                </div>
                <div class="slds-media__body">
                    <h2 class="slds-card__header-title">
                        <a href="javascript:void(0);" class="slds-card__header-link slds-truncate" title="Accounts">
                            <span class="slds-text-heading_small">Accounts</span>
                        </a>
                    </h2>
                </div>
                <div class="slds-no-flex">
                    <button class="slds-button slds-button_neutral">New</button>
                </div>
            </header>
        </div>
        <div class="slds-card__body slds-card__body_inner">Anything can go in the Card Body</div>
        <footer class="slds-card__footer">
        </footer>
    </article>
    <article class="slds-card feature-card slds-float_left slds-size--1-of-3">
        <div class="slds-card__header slds-grid">
            <header class="slds-media slds-media_center slds-has-flexi-truncate">
                <div class="slds-media__figure">
                    <span class="slds-icon_container slds-icon-standard-account" title="account">
                        
                        <span class="slds-assistive-text">account</span>
                    </span>
                </div>
                <div class="slds-media__body">
                    <h2 class="slds-card__header-title">
                        <a href="javascript:void(0);" class="slds-card__header-link slds-truncate" title="Accounts">
                            <span class="slds-text-heading_small">Accounts</span>
                        </a>
                    </h2>
                </div>
                <div class="slds-no-flex">
                    <button class="slds-button slds-button_neutral">New</button>
                </div>
            </header>
        </div>
        <div class="slds-card__body slds-card__body_inner">Anything can go in the Card Body</div>
        <footer class="slds-card__footer">
        </footer>
    </article>
    <article class="slds-card feature-card slds-float_left slds-size--1-of-3">
        <div class="slds-card__header slds-grid">
            <header class="slds-media slds-media_center slds-has-flexi-truncate">
                <div class="slds-media__figure">
                    <span class="slds-icon_container slds-icon-standard-account" title="account">
                        
                        <span class="slds-assistive-text">account</span>
                    </span>
                </div>
                <div class="slds-media__body">
                    <h2 class="slds-card__header-title">
                        <a href="javascript:void(0);" class="slds-card__header-link slds-truncate" title="Accounts">
                            <span class="slds-text-heading_small">Accounts</span>
                        </a>
                    </h2>
                </div>
                <div class="slds-no-flex">
                    <button class="slds-button slds-button_neutral">New</button>
                </div>
            </header>
        </div>
        <div class="slds-card__body slds-card__body_inner">Anything can go in the Card Body</div>
        <footer class="slds-card__footer">
        </footer>
    </article>
</div>

enter image description here

Can someone can shed some light as to the origin of this behavior and how to fix it? (is this something that should be raised with Salsforce support? – easy css fix, just throwing this out there for the community)

the same behavior results if I dont wrap the cards in a grid

Best Answer

The cards should be in their own layout boxes (instead of being the layout boxes), and should not be floating. Elements that restrict size changes (e.g. slds-size_1-of-3) should be wrapped around whatever it is you're trying to size. Most of the time it doesn't matter, but it helps to get in the habit of doing so, and doing so means using lightning:layoutItem.

Here's a self-contained demonstration using your non-dynamic card example (note: I converted this to an iteration for brevity, it still works "the long way around"):

<aura:application extends="force:slds">
    <aura:attribute name="items" type="Integer[]" default="[1,2,3,4,5,6]" />
    <div>Non Dynamic Cards</div>
        <lightning:layout multipleRows="true">
            <aura:iteration items="{!v.items}" var="item">
        <lightning:layoutItem size="4" padding="around-small">
            <lightning:card >
                <aura:set attribute="title">
                    <lightning:icon iconName="utility:connected_apps" size="small"/>
                    Card {!item}
                </aura:set>
                <aura:set attribute="footer">
                    <lightning:badge label="Tag1"/>
                    <lightning:badge label="Tag2"/>
                    <lightning:badge label="Tag3"/>
                </aura:set>
                Card Body (custom component)
            </lightning:card>
        </lightning:layoutItem>
            </aura:iteration>
    </lightning:layout>
</aura:application>

cards in a grid