DEV Community

Cover image for Tailwind CSS static navbar with shadow on scroll for Vue applications
Chris Dermody
Chris Dermody

Posted on • Originally published at chrisdermody.com

Tailwind CSS static navbar with shadow on scroll for Vue applications

I first wrote about this over on my blog - really only for my own personal reference since I'll need this code again in my next project. But thought I'd share here too.

demo of scrolling effect for shadow on navbar

If you're not using Tailwind for your CSS needs - I highly recommend it. It's now a staple of my product building toolkit, and it just fits so well with Vue.js and Nuxt workflows that I can't imagine moving to something else.

One thing about Tailwind is it leaves the Javascript to you. This is so it's library-agnostic.

For most of my projects I want that smooth shadow under the navbar - here's the code I use to achieve it.

The HTML

<nav 
    :class="{ 'scrolled': !view.atTopOfPage }" 
    class="fixed flex w-full bg-white border-b items-center justify-between flex-wrap p-5 m-auto top-0 animated">
</nav>
Enter fullscreen mode Exit fullscreen mode

Here, we're adding the .scrolled class when the value in view.atTopOfPage is false.

The CSS

I have a navbar component that I use throughout the app, so this code would go there. PS: Yes this is technically SCSS...

nav {
    z-index: 10
}

nav.scrolled {
    @apply shadow-2xl;
    border-bottom: 0px;
}
Enter fullscreen mode Exit fullscreen mode

Apply the shadow to the navbar when it has the class scrolled.

The Javascript

// in data, I like to store a view object with all 
// the values I need for a component to manage 
// it's 'view' state - ie loading, 
// or in this case, if the user is at the top of the page or not
data () {
    return {
        view: {
            atTopOfPage: true
        }
    }
},

// a beforeMount call to add a listener to the window
beforeMount () {
    window.addEventListener('scroll', this.handleScroll);
},

methods: {
    // the function to call when the user scrolls, added as a method
    handleScroll(){
        // when the user scrolls, check the pageYOffset
        if(window.pageYOffset>0){
            // user is scrolled
            if(this.view.atTopOfPage) this.view.atTopOfPage = false
        }else{
            // user is at top of page
            if(!this.view.atTopOfPage) this.view.atTopOfPage = true
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

The Result

Buttery smooth shadows on your navbar. Check it out in action on my product Referextra.com

Discussion (15)

Collapse
gfabrizi profile image
gfabrizi • Edited

Hi,

nice article!

But please, avoid doing things like:

<nav class="fixed flex w-full bg-white border-b items-center justify-between flex-wrap p-5 m-auto top-0 animated">
Enter fullscreen mode Exit fullscreen mode

this isn't different from inline style... what if you have to change text align, margin, or background color? Normally this is a css job, but with this markup you have to change your html for every cosmetic change.

If you really want to use the Tailwind classes, give your nav a single classname (like, i don't know, class="main-navbar"), then in your scss extend all the Tailwind classes under .main-navbar. This way you can leave your html clean and independent from the styling.

Collapse
khrome83 profile image
Zane Milakovic

Your thought was my initial thought also but I have revisited it.

Keeping it in the html is not as big of a issue as it use to be. It also makes it more portable, unless you are using plain css files or something that is not css in js.

This is how tailwind was designed to be used. Yes you can compose new classes with it. But that is really just making more work on yourself.

In modern web dev, like the Vue app he built, he most likely has single file components. So now if he wanted to adjust the nav bar, he will be going into that file anyways.

The big argument you are making are multiple instances of a piece of html across the site. Well, with modern development by making components you only have one place for that code in development. So it’s not extra work.

Additionally my teams have switched to TailwindCss and with the inline classes have found a few things.

  1. It’s faster to develop because the syntax is shorter and your not opening another file or moving to the style block in the same file.

  2. They still need to know css, unlike bootstrap.

  3. Code reviews have become easier, because you are not mapping classes declared somewhere else and the styles to the html.

  4. Naming things is hard, now they do a lot less of that.

  5. Our extensions have been pretty minimal, same with overrides, yet we do not look like what you might assume the theme is.

Because of many of these reasons, we may even use Alpine JS in the next project.

So I know this goes against conventional wisdom. I have been at this for almost 20 years and totally understand where your coming from. But as you can see I have come around.

Collapse
19peaches profile image
Vince Kronlein

Bravo ... that's exactly what I was thinking.

Extending makes sense if you're doing something multiple times over and over, like cards for instance or alerts. But utility first gives you far more fine grained control over your presentation.

You'll notice even boostrap has added many utility classes to mimic the tailwind paradigm.

Thanks for the code OP, this was very useful.

Collapse
josewhitetower profile image
Jose Torreblanca

I've been working with Tailwindcss for more than a year and I could not put into words, what is like to work with it. Kudos to these arguments

Collapse
codervtwo profile image
John Samuel • Edited

Great post! I'm using Vue/Nuxt, Tailwind and Firebase to build some hobbyist projects and I love it. I like having so much control and the ability to write the html and "css" at the same time in the same place.

Anyway, I have a newbie question. When I fix the nav bar like this, how do I prevent it from covering the top part of the element below (my nuxt element) ?

Collapse
chipd profile image
Chris Dermody Author

I usually add a padding/margin to the top of the body element so that all content is pushed down a little. Hope that helps

Collapse
chipd profile image
Chris Dermody Author

I'm absolutely loving Tailwind. I think it's fantastic and endlessly flexible, I never have trouble creating the UI that I need - and it slots into my Vue workflow seamlessly. With PurgeCSS it makes my CSS files crazy light. Love it.

Collapse
mnnlthmpsn profile image
JoJo Thmpsn

@gfabrizi I don't think there's an issue with inline classes when they aren't going to repeat

There's no point creating another class for a nav component when after all that will be the only component with those classes. It only saves you some time when you need to repeat them. Say a button or a card.. I stand to be corrected

Collapse
19peaches profile image
Vince Kronlein

Thanks Chris, this was really useful and drop dead simple to implement on my existing navbar.

Brilliant mate.

Collapse
chipd profile image
Chris Dermody Author

You're welcome :)

Collapse
pratik149 profile image
Pratik Rane

This is EXACTLY what I was looking for! Also it was quite easy to follow. Thank you, Chris!

Collapse
chipd profile image
Chris Dermody Author

Glad you liked it Pratik πŸ‘

Collapse
chipd profile image
Chris Dermody Author

:)