Chapters
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
CSS: Styling a Component
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Our main focus in this tutorial will be to build a rich product listing page inside of products.vue
. To get that started, I'm going to replace the h1
with some new markup - you can copy this from the code block on this page.
<template> | |
<div class="container-fluid"> | |
<div class="row"> | |
Show Lines
|
// ... lines 4 - 53 |
</div> | |
</div> | |
</template> | |
Show Lines
|
// ... lines 57 - 68 |
Notice that there is nothing special yet. We're not rendering any variables: this is 100% static HTML. If you refresh the page, ok! We have a sidebar on the left, and an area on the right where we will eventually list some products. Good start!
Global CSS and Vue Components
And, though it's not pretty, it does already have some styling. If you look back at the HTML I just pasted, the basic styling is thanks to some Bootstrap classes that are on the elements. This works because, in the assets/scss/app.scss
file, we're importing Bootstrap and I've decided to include the built app.css
file on every page. So, naturally, if we use any Bootstrap classes in Vue, those elements get styled.
Custom Component style Section
But I also want to add some extra styling that's specific to the sidebar. The question is: where should that CSS live? We could, of course, add some classes to app.scss
and use those inside our Vue component.
But Vue gives us a better option: because we want to style an element that's created in this component, Vue allows us to also put the styles in the component.
First, inside the aside
element, give this <div>
a new class called sidebar
.
<template> | |
<div class="container-fluid"> | |
<div class="row"> | |
<aside class="col-xs-12 col-3"> | |
<div class="sidebar p-3 mb-5"> | |
Show Lines
|
// ... lines 6 - 29 |
</div> | |
</aside> | |
Show Lines
|
// ... lines 32 - 53 |
</div> | |
</div> | |
</template> | |
Show Lines
|
// ... lines 57 - 76 |
Next, at the bottom - though it doesn't matter where - there is a third special section that any .vue
file can have: you can have a <template>
tag, a <script>
tag and also a <style>
tag. Inside, we're writing CSS: add .sidebar
and let's give it a border, a box-shadow
and a border-radius
.
Show Lines
|
// ... lines 1 - 68 |
<style> | |
.sidebar { | |
border: 1px solid #efefee; | |
box-shadow: 0px 0px 7px 4px #efefee; | |
border-radius: 5px; | |
} | |
</style> |
Styling done! Remember: we're still running yarn watch
in the background, so Webpack is constantly re-dumping the built JavaScript and CSS files as we're working. Thanks to that, without doing anything else, we can refresh and... the sidebar is styled!
This works thanks to some Vue and Webpack teamwork. When Webpack sees the style
tag, it grabs that CSS and puts it into the entry file's CSS file, so products.css
.
View the page source: here's the link
tag to /build/products.css
. Whenever we add any styles to any component that this entry uses, Webpack will find those and put them in here. Like a lot of things with Webpack, it's not something you really need to think about: it just works.
Using Sass Styles
So this is awesome... but I do like using Sass. If you look at webpack.config.js
, down here... yep! I've already added Sass support to Encore with .enableSassLoader()
.
Open up assets/scss/components/light-component.scss
. This is a Sass mixin that holds the exact CSS I just added manually. If we could use Sass code inside the style
tag, we could import this and save ourselves some duplication!
And that's totally possible: just add lang="scss"
.
Show Lines
|
// ... lines 1 - 68 |
<style lang="scss"> | |
Show Lines
|
// ... lines 70 - 74 |
</style> |
Now that we're writing Sass we can @import '../../scss/components/light-component'
and inside .sidebar
, @include light-component;
.
Show Lines
|
// ... lines 1 - 68 |
<style lang="scss"> | |
@import '../../scss/components/light-component'; | |
.sidebar { | |
@include light-component; | |
} | |
</style> |
Let's try it! Back over on your browser, refresh and... we have Sass!
To finish off the styling, I'll use Sass's nesting syntax to add a hover state on the links. Now after we refresh... got it!
Show Lines
|
// ... lines 1 - 71 |
.sidebar { | |
Show Lines
|
// ... lines 73 - 74 |
ul { | |
li a:hover { | |
background: $blue-component-link-hover; | |
} | |
} | |
} | |
Show Lines
|
// ... lines 81 - 82 |
Being able to put your styles right inside the component is one of my favorite features of Vue. And in a bit, we're going to do something even fancier with modular CSS.
Next, let's add some dynamic data back to our app and play with one of the coolest things in Vue: the developer tools.
21 Comments
Thanks for the tip!
In general, I would assume you could leave these flags undefined, but it definitely helps to have them!
Hey friends! We miss the code block in every video. It’s important to copy and paste in our code. The final code inside the dos loas its diferent than the current in each video. For example: all the css and html in this video. I hope yo can put them in every video like always.
Thanks
hi Alberto
Here the code :
https://github.com/SymfonyC...
Hey It O.
We are sorry about that, we have a little internal process where we add "code blocks" to the page - so they are not available immediately when chapter is released. We understand that it's a bit odd because Ryan said "copy the HTML from this page!"... but there is no HTML...yet
Anyways code blocks will be able soon!
Thanks for your attention to the details and watching new chapter as soon as it was released we really appreciate it!
Cheers!
I have a problem when i try to inject the <style>. It doesnt give an error but it does not give the syle to the page, what could be the problem?
Hmm, I'm actually not sure :/. Parsing the <style>
tag is the job of Webpack + the vue-loader that works with Webpack. I would try mis-typing style - e.g. <stly>
just to see if you can trigger a build error in Webpack (and thus, make sure it's parsing this file correctly).
Cheers!
Hey Ryan + Team,
I know this issues does not really belong to this lecture, however, I could not find any solution to my issue in other lectures or on the web, so I decided to ask this here.
The point is, that I want to use a static image inside my vue component. The image lives in assets/static/images/image.jpg.
Referencing the image with <img src="/build/images/image.jpg">
does work, however, I am using .enableVersioning(Encore.isProduction())
in my webpack.config.js. So with hashing I don't know how to reference my image anymore since the hash changes for every build.
In twig this is usually handled like this, as far as I know: src="{{ asset('build/images/image.jpg') }}"
(from manifest.json)
Is there a way to handle this problem in vue as well? :-)
Cheers!
Hey @Luca!
Great timing on this - I just answered this question a day or two ago :). The tl;dr is that it's easy! But... due to bad behavior between a few libraries... it's only kinda easy :p. Here is the answer: https://symfonycasts.com/sc...
On a philosophical Webpack level, the answer is "just import the image in the same way you would import another JavaScript file", which is kinda cool ;).
Let me know if that helps!
Cheers!
Hey! It does not work for me. If I write simple css at the end of my vue-file, it will not include anything. It is simply ignored and does not work at all. Any ideas? I've done everything one-to-one...
Hey @Jakob!
Hmm. Can you post your Vue file for us? I know you're doing everything one-to-one, but maybe there is something tiny that's wrong - that's the hardest stuff to find :). Also, what version of vue, vue-loader, vue-style-loader and vue-template-compiler do you have? You can find this by running yarn list --depth=0
.
Oh, and two more things - if you view source on the page, do you see a link tag for products.css? I want to make sure that is being included on the page (it is if you started with our code), And finally, when you run yarn watch
what files does it say it is rendering? Do you see a products.css there?
Cheers!
Hey, thank you for your answer!
├─ vue-hot-reload-api@2.3.4
├─ vue-loader@15.9.3
├─ vue-style-loader@4.1.2
├─ vue-template-compiler@2.6.11
├─ vue-template-es2015-compiler@1.9.1
├─ vue@2.6.11
I've just a style tag in the end of the template🙂
I am one step further: The .css is packed into the js directory, but it is not included on the page
I fixed it - Thank you very much for your answer :)
Hey @Jakob!
Nice work! What was the final solution?
Cheers!
Hey!
I think one package was missing, I deleted node_modules and ran yarn install again :) It was a little weird, but now it works perfectly😀
Hey! unfortunately i have the same problem and this solution didn't work. The css file is not created ☹️
Hi Caprarolainfo!
Can you tell us a little bit more about your issue? Have you looked into your packages.json to see if your packages are all there and are the latest versions? That does seem like a webpack issue to me!
Let me know what you can find!
Hi Matias Jose!
Sorry if I wasted your time, I found the problem. 😳I wrote the link encore_entry_link_tags wrong. Now everything works.
Thanks so much
No problem! I'm glad you've found it! :)
"Houston: no signs of life"
Start the conversation!
What JavaScript libraries does this tutorial use?
// package.json
{
"devDependencies": {
"@symfony/webpack-encore": "^0.30.0", // 0.30.2
"axios": "^0.19.2", // 0.19.2
"bootstrap": "^4.4.1", // 4.5.0
"core-js": "^3.0.0", // 3.6.5
"eslint": "^6.7.2", // 6.8.0
"eslint-config-airbnb-base": "^14.0.0", // 14.1.0
"eslint-plugin-import": "^2.19.1", // 2.20.2
"eslint-plugin-vue": "^6.0.1", // 6.2.2
"regenerator-runtime": "^0.13.2", // 0.13.5
"sass": "^1.29.0", // 1.29.0
"sass-loader": "^8.0.0", // 8.0.2
"vue": "^2.6.11", // 2.6.11
"vue-loader": "^15.9.1", // 15.9.2
"vue-template-compiler": "^2.6.11", // 2.6.11
"webpack-notifier": "^1.6.0" // 1.8.0
}
}
Here's a warning I see in my console (using Vue 3).
<blockquote>
Feature flags VUE_OPTIONS_API, VUE_PROD_DEVTOOLS are not explicitly defined. You are running the esm-bundler build of Vue, which expects these compile-time feature flags to be globally injected via the bundler config in order to get better tree-shaking in the production bundle.
For more details, see https://link.vuejs.org/feature-flags.
</blockquote>I was about to ask you to spoon-feed me the answer but then sighed and did my own homework like a good citizen. :-) PhpStorm's hinting and autocompleting makes it so easy even a noob can muddle through! You can get rid of this warning by adding this to webpack.config.js: