Vue.js 根据浏览器动态支持的内容,如何在使用网格布局的模板和使用Flex的模板之间切换?

Vue.js 根据浏览器动态支持的内容,如何在使用网格布局的模板和使用Flex的模板之间切换?,vue.js,vuejs2,flexbox,vue-component,css-grid,Vue.js,Vuejs2,Flexbox,Vue Component,Css Grid,我有以下代码 HTML body #__nuxt #__layout //- CSS Grid .news-item(:key="item.feed_item_id" :ref="item.feed_item_id" role="listitem" tabindex="0") .news-item-

我有以下代码

HTML

body
    #__nuxt
        #__layout
            //-         CSS Grid
            .news-item(:key="item.feed_item_id" :ref="item.feed_item_id" role="listitem" tabindex="0")
                .news-item-pubdate 1m 
                .news-item-title(:style="titleStyle") {{item.title}}
                    span.news-item-link  example.com
                .news-item-likes
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-thumbs-up
                    span.news-item-vote-count {{item.likes}}
                .news-item-dislikes
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-thumbs-down
                    span.news-item-vote-count {{item.dislikes}}
                .news-item-bullish
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-arrow-up
                    span.news-item-vote-count {{item.bullish}}
                .news-item-bearish
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-arrow-down
                    span.news-item-vote-count {{item.bearish}}
                .news-item-comments
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-comment-alt
                    span.news-item-vote-count 0
                .news-item-tags.has-text-right(:style="tagStyle")
                    .news-item-tag(v-for='(tag, i) in item.tags' :key='item.tag' @click.stop="updateTag(tag)")
                        a.button.is-paddingless.is-small.is-uppercase.is-text
                            |{{tag}}
                            span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
                            span(v-else)    
            //-             Flexbox
            .news-item2(:key="item.feed_item_id" :ref="item.feed_item_id" role="listitem" tabindex="0")
                .news-item-pubdate-wrapper
                    .news-item-pubdate2 1m  
                .news-item-content-wrapper
                    .news-item-title-wrapper
                        .news-item-title2(:style="titleStyle") {{item.title}}
                            span.news-item-link2  example.com
                    .news-item-votes-wrapper
                        .news-item-likes2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-thumbs-up
                            span.news-item-vote-count2 {{item.likes}}
                        .news-item-dislikes2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-thumbs-down
                            span.news-item-vote-count2 {{item.dislikes}}
                        .news-item-bullish2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-arrow-up
                            span.news-item-vote-count2 {{item.bullish}}
                        .news-item-bearish2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-arrow-down
                            span.news-item-vote-count2 {{item.bearish}}
                        .news-item-comments2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-comment-alt
                            span.news-item-vote-count2 0
                .news-item-tags-wrapper
                    .news-item-tags2.has-text-right(:style="tagStyle")
                        .news-item-tag2(v-for='(tag, i) in item.tags' :key='item.tag' @click.stop="updateTag(tag)")
                            a.button.is-paddingless.is-small.is-uppercase.is-text
                                |{{tag}}
                                span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
                                span(v-else)    
script#flex(type="text/x-template")
    .news-item2(
        :key="item.feed_item_id",
        :ref="item.feed_item_id",
        role="listitem",
        tabindex="0"
    )
        .news-item-pubdate-wrapper
            .news-item-pubdate2 1m  
        .news-item-content-wrapper
            .news-item-title-wrapper
                .news-item-title2(:style="titleStyle") {{ item.title }}
                    span.news-item-link2  example.com
            .news-item-votes-wrapper
                .news-item-likes2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-thumbs-up
                    span.news-item-vote-count2 {{ item.likes }}
                .news-item-dislikes2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-thumbs-down
                    span.news-item-vote-count2 {{ item.dislikes }}
                .news-item-bullish2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-arrow-up
                    span.news-item-vote-count2 {{ item.bullish }}
                .news-item-bearish2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-arrow-down
                    span.news-item-vote-count2 {{ item.bearish }}
                .news-item-comments2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-comment-alt
                    span.news-item-vote-count2 0
        .news-item-tags-wrapper
            .news-item-tags2.has-text-right(:style="tagStyle")
                .news-item-tag2(
                    v-for="(tag, i) in item.tags",
                    :key="item.tag",
                    @click.stop="updateTag(tag)"
                )
                    a.button.is-paddingless.is-small.is-uppercase.is-text
                        | {{ tag }}
                        span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
                        span(v-else)    

script#grid(type="text/x-template")
    .news-item(
        :key="item.feed_item_id",
        :ref="item.feed_item_id",
        role="listitem",
        tabindex="0"
    )
        .news-item-pubdate 1m 
        .news-item-title(:style="titleStyle") {{ item.title }}
            span.news-item-link  example.com
        .news-item-likes
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-thumbs-up
            span.news-item-vote-count {{ item.likes }}
        .news-item-dislikes
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-thumbs-down
            span.news-item-vote-count {{ item.dislikes }}
        .news-item-bullish
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-arrow-up
            span.news-item-vote-count {{ item.bullish }}
        .news-item-bearish
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-arrow-down
            span.news-item-vote-count {{ item.bearish }}
        .news-item-comments
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-comment-alt
            span.news-item-vote-count 0
        .news-item-tags.has-text-right(:style="tagStyle")
            .news-item-tag(
                v-for="(tag, i) in item.tags",
                :key="item.tag",
                @click.stop="updateTag(tag)"
            )
                a.button.is-paddingless.is-small.is-uppercase.is-text
                    | {{ tag }}
                    span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
                    span(v-else)    

script#item(type="text/x-template")
    template(v-if="supportsCssGrid", :item="item")
        grid(:item="item")
    template(v-else)
        flex(:item="item")

body
    #__nuxt
        #__layout
            item(:item="item")
CSS

/**
Using CSS GRID
*/

:root {
    --border-color: lightgray;
}

$grey: hsl(0, 0%, 48%);
$grey-light: hsl(0, 0%, 71%);
$size-7: 0.75rem;
$warning-light: hsl(48, 100%, 67%);

.news-item {
  display: grid;
  grid-template-areas:
    'time title title title title title title tags'
    'time likes dislikes bullish bearish comments . tags';
  grid-template-rows: 1fr auto;
  grid-template-columns: auto auto auto auto auto auto 1fr auto;
  border-bottom: 1px solid var(--border-color);
}

.news-item-title {
  grid-area: title;
    overflow: hidden;
}

.news-item-likes {
  grid-area: likes;
}

.news-item-dislikes {
  grid-area: dislikes;
}

.news-item-bullish {
  grid-area: bullish;
}

.news-item-bearish {
  grid-area: bearish;
}

.news-item-comments {
  grid-area: comments;
}

.news-item-tags {
  grid-area: tags;
    overflow: hidden;
}

a.news-item-tag {
  color: $grey;
  text-decoration: none;
}

.news-item-link {
  color: $grey;
  font-size: $size-7;
}

.news-item-pubdate {
  grid-area: time;
  align-self: center;
  color: $grey-light;
  font-size: $size-7;
}

.news-item-vote-icon {
  color: $grey-light;
  margin-right: 0.1rem;
}

.news-item-vote-count {
  font-size: 0.75rem;
  margin-right: 0.5rem;
  color: $grey-light;
}

.news-item-selected {
  background: $warning-light;
}

/** https://stackoverflow.com/questions/23608346/how-to-style-a-div-like-the-button-element */
.news-item {
  cursor: pointer;
  user-select: none;
}

a.button.is-paddingless.is-small.is-uppercase.is-text {
  text-decoration: none;
  line-height: 1.5;
  color: $grey;
}

/**
Using FLEXBOX
*/

.news-item2 {
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--border-color);
}

.news-item-content-wrapper {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.news-item-votes-wrapper {
    display: flex;
}

.news-item-title2 {
    overflow: hidden;
}

.news-item-link2 {
  color: $grey;
  font-size: $size-7;
}

.news-item-pubdate2 {
  grid-area: time;
  align-self: center;
  color: $grey-light;
  font-size: $size-7;
}

.news-item-vote-icon2 {
  color: $grey-light;
  margin-right: 0.1rem;
}

.news-item-vote-count2 {
  font-size: 0.75rem;
  margin-right: 0.5rem;
  color: $grey-light;
}

.news-item-tags2 {
    overflow: hidden;
}
new Vue({
    el: "#__nuxt",
    data() {
        return {
            item: {
                feed_item_id: 1,
                title: 'The first one is made with a grid layout while the second one is made with a flex layout. The templates are different, how do I load the right one based on what is supported by the browser?',
                tags: ['trump', 'putin', 'defi'],
                likes: 10,
                dislikes: 5,
                bullish: 6,
                bearish: 0,
            },
            lineCountTag: 2,
            lineCountTitle: 2,
            heightPerLineTag: 30,
            heightPerLineTitle: 24,
        };
    },
    computed: {
        tagStyle() {
            return {
                height: this.heightPerLineTag * this.lineCountTag + "px",
                maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
            };
        },
        titleStyle() {
            return {
                height: this.heightPerLineTitle * this.lineCountTitle + "px",
                maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
            };
        }
    }
});
const lineClamp = {
    data() {
        return {
            lineCountTag: 2,
            lineCountTitle: 2,
            heightPerLineTag: 30,
            heightPerLineTitle: 24
        };
    },
    computed: {
        tagStyle() {
            return {
                height: this.heightPerLineTag * this.lineCountTag + "px",
                maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
            };
        },
        titleStyle() {
            return {
                height: this.heightPerLineTitle * this.lineCountTitle + "px",
                maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
            };
        }
    }
};

Vue.component("flex", {
    template: "#flex",
    mixins: [lineClamp],
    props: {
        item: {
            type: Object,
            default: () => {},
            required: true
        }
    }
});

Vue.component("grid", {
    template: "#grid",
    mixins: [lineClamp],
    props: {
        item: {
            type: Object,
            default: () => {},
            required: true
        }
    }
});

Vue.component("item", {
    template: "#item",
    props: {
        item: {
            type: Object,
            default: () => {},
            required: true
        }
    },
    computed: {
        supportsCssGrid() {
            return CSS.supports("display", "grid");
        }
    }
});

new Vue({
    el: "#__nuxt",
    data() {
        return {
            item: {
                feed_item_id: 1,
                title:
                    "The first one is made with a grid layout while the second one is made with a flex layout. The templates are different, how do I load the right one based on what is supported by the browser?",
                tags: ["trump", "putin", "defi"],
                likes: 10,
                dislikes: 5,
                bullish: 6,
                bearish: 0
            },
            lineCountTag: 2,
            lineCountTitle: 2,
            heightPerLineTag: 30,
            heightPerLineTitle: 24
        };
    },
    computed: {
        tagStyle() {
            return {
                height: this.heightPerLineTag * this.lineCountTag + "px",
                maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
            };
        },
        titleStyle() {
            return {
                height: this.heightPerLineTitle * this.lineCountTitle + "px",
                maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
            };
        }
    }
});
Vue JS

/**
Using CSS GRID
*/

:root {
    --border-color: lightgray;
}

$grey: hsl(0, 0%, 48%);
$grey-light: hsl(0, 0%, 71%);
$size-7: 0.75rem;
$warning-light: hsl(48, 100%, 67%);

.news-item {
  display: grid;
  grid-template-areas:
    'time title title title title title title tags'
    'time likes dislikes bullish bearish comments . tags';
  grid-template-rows: 1fr auto;
  grid-template-columns: auto auto auto auto auto auto 1fr auto;
  border-bottom: 1px solid var(--border-color);
}

.news-item-title {
  grid-area: title;
    overflow: hidden;
}

.news-item-likes {
  grid-area: likes;
}

.news-item-dislikes {
  grid-area: dislikes;
}

.news-item-bullish {
  grid-area: bullish;
}

.news-item-bearish {
  grid-area: bearish;
}

.news-item-comments {
  grid-area: comments;
}

.news-item-tags {
  grid-area: tags;
    overflow: hidden;
}

a.news-item-tag {
  color: $grey;
  text-decoration: none;
}

.news-item-link {
  color: $grey;
  font-size: $size-7;
}

.news-item-pubdate {
  grid-area: time;
  align-self: center;
  color: $grey-light;
  font-size: $size-7;
}

.news-item-vote-icon {
  color: $grey-light;
  margin-right: 0.1rem;
}

.news-item-vote-count {
  font-size: 0.75rem;
  margin-right: 0.5rem;
  color: $grey-light;
}

.news-item-selected {
  background: $warning-light;
}

/** https://stackoverflow.com/questions/23608346/how-to-style-a-div-like-the-button-element */
.news-item {
  cursor: pointer;
  user-select: none;
}

a.button.is-paddingless.is-small.is-uppercase.is-text {
  text-decoration: none;
  line-height: 1.5;
  color: $grey;
}

/**
Using FLEXBOX
*/

.news-item2 {
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--border-color);
}

.news-item-content-wrapper {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.news-item-votes-wrapper {
    display: flex;
}

.news-item-title2 {
    overflow: hidden;
}

.news-item-link2 {
  color: $grey;
  font-size: $size-7;
}

.news-item-pubdate2 {
  grid-area: time;
  align-self: center;
  color: $grey-light;
  font-size: $size-7;
}

.news-item-vote-icon2 {
  color: $grey-light;
  margin-right: 0.1rem;
}

.news-item-vote-count2 {
  font-size: 0.75rem;
  margin-right: 0.5rem;
  color: $grey-light;
}

.news-item-tags2 {
    overflow: hidden;
}
new Vue({
    el: "#__nuxt",
    data() {
        return {
            item: {
                feed_item_id: 1,
                title: 'The first one is made with a grid layout while the second one is made with a flex layout. The templates are different, how do I load the right one based on what is supported by the browser?',
                tags: ['trump', 'putin', 'defi'],
                likes: 10,
                dislikes: 5,
                bullish: 6,
                bearish: 0,
            },
            lineCountTag: 2,
            lineCountTitle: 2,
            heightPerLineTag: 30,
            heightPerLineTitle: 24,
        };
    },
    computed: {
        tagStyle() {
            return {
                height: this.heightPerLineTag * this.lineCountTag + "px",
                maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
            };
        },
        titleStyle() {
            return {
                height: this.heightPerLineTitle * this.lineCountTitle + "px",
                maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
            };
        }
    }
});
const lineClamp = {
    data() {
        return {
            lineCountTag: 2,
            lineCountTitle: 2,
            heightPerLineTag: 30,
            heightPerLineTitle: 24
        };
    },
    computed: {
        tagStyle() {
            return {
                height: this.heightPerLineTag * this.lineCountTag + "px",
                maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
            };
        },
        titleStyle() {
            return {
                height: this.heightPerLineTitle * this.lineCountTitle + "px",
                maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
            };
        }
    }
};

Vue.component("flex", {
    template: "#flex",
    mixins: [lineClamp],
    props: {
        item: {
            type: Object,
            default: () => {},
            required: true
        }
    }
});

Vue.component("grid", {
    template: "#grid",
    mixins: [lineClamp],
    props: {
        item: {
            type: Object,
            default: () => {},
            required: true
        }
    }
});

Vue.component("item", {
    template: "#item",
    props: {
        item: {
            type: Object,
            default: () => {},
            required: true
        }
    },
    computed: {
        supportsCssGrid() {
            return CSS.supports("display", "grid");
        }
    }
});

new Vue({
    el: "#__nuxt",
    data() {
        return {
            item: {
                feed_item_id: 1,
                title:
                    "The first one is made with a grid layout while the second one is made with a flex layout. The templates are different, how do I load the right one based on what is supported by the browser?",
                tags: ["trump", "putin", "defi"],
                likes: 10,
                dislikes: 5,
                bullish: 6,
                bearish: 0
            },
            lineCountTag: 2,
            lineCountTitle: 2,
            heightPerLineTag: 30,
            heightPerLineTitle: 24
        };
    },
    computed: {
        tagStyle() {
            return {
                height: this.heightPerLineTag * this.lineCountTag + "px",
                maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
            };
        },
        titleStyle() {
            return {
                height: this.heightPerLineTitle * this.lineCountTitle + "px",
                maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
            };
        }
    }
});
  • 我做了两行,第一行是网格布局
  • 第二个使用flexbox布局
  • 我想要一个Vue组件,它基本上可以加载其中一个组件,具体取决于浏览器是否支持flexbox或grid
  • 问题是这些模板彼此不同
  • 我该怎么做

我想我明白了,需要2个单独的组件,一个带有flex,另一个带有css网格作为结构,不能在一个组件中同时包含这两个组件,因为使用css网格和flexbox时项目的结构布局不同,制作第三个组件,使用计算属性css.supports检查JS中是否支持css网格(“显示”、“网格”)

HTML

body
    #__nuxt
        #__layout
            //-         CSS Grid
            .news-item(:key="item.feed_item_id" :ref="item.feed_item_id" role="listitem" tabindex="0")
                .news-item-pubdate 1m 
                .news-item-title(:style="titleStyle") {{item.title}}
                    span.news-item-link  example.com
                .news-item-likes
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-thumbs-up
                    span.news-item-vote-count {{item.likes}}
                .news-item-dislikes
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-thumbs-down
                    span.news-item-vote-count {{item.dislikes}}
                .news-item-bullish
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-arrow-up
                    span.news-item-vote-count {{item.bullish}}
                .news-item-bearish
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-arrow-down
                    span.news-item-vote-count {{item.bearish}}
                .news-item-comments
                    span.icon.is-small.news-item-vote-icon
                        i.fa.fa-xs.fa-comment-alt
                    span.news-item-vote-count 0
                .news-item-tags.has-text-right(:style="tagStyle")
                    .news-item-tag(v-for='(tag, i) in item.tags' :key='item.tag' @click.stop="updateTag(tag)")
                        a.button.is-paddingless.is-small.is-uppercase.is-text
                            |{{tag}}
                            span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
                            span(v-else)    
            //-             Flexbox
            .news-item2(:key="item.feed_item_id" :ref="item.feed_item_id" role="listitem" tabindex="0")
                .news-item-pubdate-wrapper
                    .news-item-pubdate2 1m  
                .news-item-content-wrapper
                    .news-item-title-wrapper
                        .news-item-title2(:style="titleStyle") {{item.title}}
                            span.news-item-link2  example.com
                    .news-item-votes-wrapper
                        .news-item-likes2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-thumbs-up
                            span.news-item-vote-count2 {{item.likes}}
                        .news-item-dislikes2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-thumbs-down
                            span.news-item-vote-count2 {{item.dislikes}}
                        .news-item-bullish2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-arrow-up
                            span.news-item-vote-count2 {{item.bullish}}
                        .news-item-bearish2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-arrow-down
                            span.news-item-vote-count2 {{item.bearish}}
                        .news-item-comments2
                            span.icon.is-small.news-item-vote-icon2
                                i.fa.fa-xs.fa-comment-alt
                            span.news-item-vote-count2 0
                .news-item-tags-wrapper
                    .news-item-tags2.has-text-right(:style="tagStyle")
                        .news-item-tag2(v-for='(tag, i) in item.tags' :key='item.tag' @click.stop="updateTag(tag)")
                            a.button.is-paddingless.is-small.is-uppercase.is-text
                                |{{tag}}
                                span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
                                span(v-else)    
script#flex(type="text/x-template")
    .news-item2(
        :key="item.feed_item_id",
        :ref="item.feed_item_id",
        role="listitem",
        tabindex="0"
    )
        .news-item-pubdate-wrapper
            .news-item-pubdate2 1m  
        .news-item-content-wrapper
            .news-item-title-wrapper
                .news-item-title2(:style="titleStyle") {{ item.title }}
                    span.news-item-link2  example.com
            .news-item-votes-wrapper
                .news-item-likes2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-thumbs-up
                    span.news-item-vote-count2 {{ item.likes }}
                .news-item-dislikes2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-thumbs-down
                    span.news-item-vote-count2 {{ item.dislikes }}
                .news-item-bullish2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-arrow-up
                    span.news-item-vote-count2 {{ item.bullish }}
                .news-item-bearish2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-arrow-down
                    span.news-item-vote-count2 {{ item.bearish }}
                .news-item-comments2
                    span.icon.is-small.news-item-vote-icon2
                        i.fa.fa-xs.fa-comment-alt
                    span.news-item-vote-count2 0
        .news-item-tags-wrapper
            .news-item-tags2.has-text-right(:style="tagStyle")
                .news-item-tag2(
                    v-for="(tag, i) in item.tags",
                    :key="item.tag",
                    @click.stop="updateTag(tag)"
                )
                    a.button.is-paddingless.is-small.is-uppercase.is-text
                        | {{ tag }}
                        span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
                        span(v-else)    

script#grid(type="text/x-template")
    .news-item(
        :key="item.feed_item_id",
        :ref="item.feed_item_id",
        role="listitem",
        tabindex="0"
    )
        .news-item-pubdate 1m 
        .news-item-title(:style="titleStyle") {{ item.title }}
            span.news-item-link  example.com
        .news-item-likes
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-thumbs-up
            span.news-item-vote-count {{ item.likes }}
        .news-item-dislikes
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-thumbs-down
            span.news-item-vote-count {{ item.dislikes }}
        .news-item-bullish
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-arrow-up
            span.news-item-vote-count {{ item.bullish }}
        .news-item-bearish
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-arrow-down
            span.news-item-vote-count {{ item.bearish }}
        .news-item-comments
            span.icon.is-small.news-item-vote-icon
                i.fa.fa-xs.fa-comment-alt
            span.news-item-vote-count 0
        .news-item-tags.has-text-right(:style="tagStyle")
            .news-item-tag(
                v-for="(tag, i) in item.tags",
                :key="item.tag",
                @click.stop="updateTag(tag)"
            )
                a.button.is-paddingless.is-small.is-uppercase.is-text
                    | {{ tag }}
                    span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
                    span(v-else)    

script#item(type="text/x-template")
    template(v-if="supportsCssGrid", :item="item")
        grid(:item="item")
    template(v-else)
        flex(:item="item")

body
    #__nuxt
        #__layout
            item(:item="item")
Vue JS

/**
Using CSS GRID
*/

:root {
    --border-color: lightgray;
}

$grey: hsl(0, 0%, 48%);
$grey-light: hsl(0, 0%, 71%);
$size-7: 0.75rem;
$warning-light: hsl(48, 100%, 67%);

.news-item {
  display: grid;
  grid-template-areas:
    'time title title title title title title tags'
    'time likes dislikes bullish bearish comments . tags';
  grid-template-rows: 1fr auto;
  grid-template-columns: auto auto auto auto auto auto 1fr auto;
  border-bottom: 1px solid var(--border-color);
}

.news-item-title {
  grid-area: title;
    overflow: hidden;
}

.news-item-likes {
  grid-area: likes;
}

.news-item-dislikes {
  grid-area: dislikes;
}

.news-item-bullish {
  grid-area: bullish;
}

.news-item-bearish {
  grid-area: bearish;
}

.news-item-comments {
  grid-area: comments;
}

.news-item-tags {
  grid-area: tags;
    overflow: hidden;
}

a.news-item-tag {
  color: $grey;
  text-decoration: none;
}

.news-item-link {
  color: $grey;
  font-size: $size-7;
}

.news-item-pubdate {
  grid-area: time;
  align-self: center;
  color: $grey-light;
  font-size: $size-7;
}

.news-item-vote-icon {
  color: $grey-light;
  margin-right: 0.1rem;
}

.news-item-vote-count {
  font-size: 0.75rem;
  margin-right: 0.5rem;
  color: $grey-light;
}

.news-item-selected {
  background: $warning-light;
}

/** https://stackoverflow.com/questions/23608346/how-to-style-a-div-like-the-button-element */
.news-item {
  cursor: pointer;
  user-select: none;
}

a.button.is-paddingless.is-small.is-uppercase.is-text {
  text-decoration: none;
  line-height: 1.5;
  color: $grey;
}

/**
Using FLEXBOX
*/

.news-item2 {
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--border-color);
}

.news-item-content-wrapper {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.news-item-votes-wrapper {
    display: flex;
}

.news-item-title2 {
    overflow: hidden;
}

.news-item-link2 {
  color: $grey;
  font-size: $size-7;
}

.news-item-pubdate2 {
  grid-area: time;
  align-self: center;
  color: $grey-light;
  font-size: $size-7;
}

.news-item-vote-icon2 {
  color: $grey-light;
  margin-right: 0.1rem;
}

.news-item-vote-count2 {
  font-size: 0.75rem;
  margin-right: 0.5rem;
  color: $grey-light;
}

.news-item-tags2 {
    overflow: hidden;
}
new Vue({
    el: "#__nuxt",
    data() {
        return {
            item: {
                feed_item_id: 1,
                title: 'The first one is made with a grid layout while the second one is made with a flex layout. The templates are different, how do I load the right one based on what is supported by the browser?',
                tags: ['trump', 'putin', 'defi'],
                likes: 10,
                dislikes: 5,
                bullish: 6,
                bearish: 0,
            },
            lineCountTag: 2,
            lineCountTitle: 2,
            heightPerLineTag: 30,
            heightPerLineTitle: 24,
        };
    },
    computed: {
        tagStyle() {
            return {
                height: this.heightPerLineTag * this.lineCountTag + "px",
                maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
            };
        },
        titleStyle() {
            return {
                height: this.heightPerLineTitle * this.lineCountTitle + "px",
                maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
            };
        }
    }
});
const lineClamp = {
    data() {
        return {
            lineCountTag: 2,
            lineCountTitle: 2,
            heightPerLineTag: 30,
            heightPerLineTitle: 24
        };
    },
    computed: {
        tagStyle() {
            return {
                height: this.heightPerLineTag * this.lineCountTag + "px",
                maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
            };
        },
        titleStyle() {
            return {
                height: this.heightPerLineTitle * this.lineCountTitle + "px",
                maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
            };
        }
    }
};

Vue.component("flex", {
    template: "#flex",
    mixins: [lineClamp],
    props: {
        item: {
            type: Object,
            default: () => {},
            required: true
        }
    }
});

Vue.component("grid", {
    template: "#grid",
    mixins: [lineClamp],
    props: {
        item: {
            type: Object,
            default: () => {},
            required: true
        }
    }
});

Vue.component("item", {
    template: "#item",
    props: {
        item: {
            type: Object,
            default: () => {},
            required: true
        }
    },
    computed: {
        supportsCssGrid() {
            return CSS.supports("display", "grid");
        }
    }
});

new Vue({
    el: "#__nuxt",
    data() {
        return {
            item: {
                feed_item_id: 1,
                title:
                    "The first one is made with a grid layout while the second one is made with a flex layout. The templates are different, how do I load the right one based on what is supported by the browser?",
                tags: ["trump", "putin", "defi"],
                likes: 10,
                dislikes: 5,
                bullish: 6,
                bearish: 0
            },
            lineCountTag: 2,
            lineCountTitle: 2,
            heightPerLineTag: 30,
            heightPerLineTitle: 24
        };
    },
    computed: {
        tagStyle() {
            return {
                height: this.heightPerLineTag * this.lineCountTag + "px",
                maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
            };
        },
        titleStyle() {
            return {
                height: this.heightPerLineTitle * this.lineCountTitle + "px",
                maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
            };
        }
    }
});