Use CSS class in another CSS file - html

I have Asp.net Core 5.0.1 app with multiple MVC views. I also have a CSS file, generated by an app. I want this file to be unmodified (as it will be changed in future using same app). I want separate CSS file, which styles certain elements (eg input or button) to be styled using classes from the generated CSS. I dont want to write class on each input or button etc element (there are 35 views needs to be styled).
For example if generated file has class dx-theme-text-color I want a CSS file which has something like input { color:.dx-theme-text-color}
How can I achieve this?
To clarify: the question is - how to use a class from one CSS in another by name not copy/pasting values etc

I can only think of #extend from SASS:
.dx-theme-text-color {
border: 1px solid red;
}
input, button {
#extend .dx-theme-text-color;
}

You can use css variables.
define css variavles in global scope:
:root {
--my-custom-color: #000;
}
use variables in every css file like this:
.my-element {
color: var(--my-costum-color)
}
You can also use css pre-proccesors like sass(scss), less and etc.

Related

How to place style.css behind style tags added by angular material

I've added angular material to my project and after creating a custom theme I wanted to change the style of .mat-fab.
_theme.scss:
#use '~#angular/material' as mat;
#include mat.core();
$wb-nightblue: ( ... );
$wb-yellow: ( ... );
$wb-primary: mat.define-palette($wb-nightblue);
$wb-accent: mat.define-palette($wb-yellow, 500, 300, 800);
$wb-warn: mat.define-palette(mat.$red-palette);
$wb-theme: mat.define-dark-theme((color: (primary: $wb-primary, accent: $wb-accent, warn: $wb-warn)));
#include mat.all-component-themes($wb-theme);
.mat-fab {
border-radius: 3px;
}
styles.scss:
/* You can add global styles to this file, and also import other style files */
#import '_theme';
The mat-fab button still doesn't show my custom border-radius, however. Taking a look at the page with the dev-tools I can see that my css-rule exists, but it is overwritten by the default material style. Apparently, angular material adds four <style>-tags to the end of the HTML header, just after my stylesheet gets added by angular, which then overwrite my added style.
...
<link rel="stylesheet" href="styles.css">
<style>/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJhcHAuY29tcG9uZW50LnNjc3MifQ== */</style>
<style>.mat-button .mat-button-focu...</style> // contains a lot of angular material button related styles.
<style>.mat-icon{background-repeat:...</style> // contains some angular material icon related styles.
<style>/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJtYXAuY29tcG9uZW50LnNjc3MifQ== */</style>
</head>
Now this construct makes it of course pretty much impossible for me to overwrite default button styles without resorting to !important. I don't know what the sourceMappingURL styles are doing but I guessed they're responsible for the other two tags being added. I've tried to look for them in my project but couldn't find anything. Google wasn't any help either. If I just remove the styles in the html via developer tools, the buttons then lack the proper material style so they are required, but I'd like to have my styles.css placed at the end of the HTML head, so I can overwrite the parts I want.
I've also checked angular.json for any style entries but the only one is my styles.css, which isn't any surprise, since I'd have other stylesheet links in there instead of the direct <style>-tags.
Is there a way to get my stylesheet to the end of the head?
UPDATE
The reason the below does not work has nothing to do with Angular, but with CSS.
.mat-fab {
border-radius: 3px;
}
Basically, CSS applies styles according to how specific they are.
If you want a style to be applied over another one, you need to be more specific about it.
You can read more on this here.
Now onto possible solutions, which are three:
The important!:
A way to make your styles always apply over another is the use of the important! attribute.
This means that your style will only be overwritten by another style with an important! that is more specific that yours.
Given that Angular Material avoids important! there is little change that this happens. The solution would then be:
.mat-fab {
border-radius: 3px !important;
}
Being more specific with material styles:
Lots of people see the use of important! has an indicator that the CSS was poorly written. An alternative to this is simply being more specific with material on what styles we want to overwrite, like so:
.mat-button-base.mat-fab {
border-radius: 3px;
}
In this case we are using Material's own class to specific that we want to apply our style not just to the mat-fab but to a html element that contains both mat-fab and mat-button-base.
The mat-button-base class is a class that all buttons from Angular Material share.
Define your own class and combine it:
Similar to the previous sugestion, instead of using angular material, you can create your own class and combine it with the mat-fab like so:
.border-3.mat-fab {
border-radius: 3px;
}
And in the html you would have:
<button mat-fab class="border-3">
<mat-icon><!-- Icon here --></mat-icon>
</button>
This approach is clearer if somethings you will use the original material style and sometimes your own styling.
Keep in mind that in all cases, the styles need to be defined in a global style sheet.
According to the Official Documentation if you want to override the style of material component, you should create a file with all your custom styles, them pass it to the styles array of your angular.json.
The above describes how to find it:
{
"$schema": "./node_modules/#angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"app-name": {
...
"architect": {
"build": {
"options": {
...
// Add the file here.
"styles": [
// By default, Angular adds the material theme you choose and the src/style.scss file, see below
"./node_modules/#angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.scss"
],
}
}
}
}
}
}
The file you are edditing is related to theming (color palettes and what not).
An example of this is the src/style.scss file. This file is created by default to allow you to create css that will be applied to all HTML Elements and components.
With the above in mind, I would advise that you add your code in the src/style.scss file like below:
/* You can add global styles to this file, and also import other style files */
.mat-fab {
border-radius: 3px;
}

Angular is ignoring the style class set on less files

For some reason my Angular app doesn't use the styles I'm defining at my component's .less file. It simply ignore it.
As I am very newbie with CSS, I don't any way to debug it.
My layout is consisted by a lot of defined styles being imported by other less files. I am using trying to modify the style of a mapboxgl.
This is how the map current looks like:
And it's defined on HTML by:
<div eds-tile class="column xl-3">
<eds-tile-title>Location</eds-tile-title>
<eds-tile-actions>
<div class="action">
<eds-icon icon="maximize">
</eds-icon>
</div>
</eds-tile-actions>
<div class="map" id="map"></div>
</div>
On this component's less I have:
#import "~#eds/vanilla/variables/light";
#import (reference) "~#eds/vanilla/font/styles";
#import (reference, multiple) "~#eds/vanilla/variables/global";
#import "./map/map";
And on ./map/map.less I have a lot of theme stylization:
https://pastebin.com/b8CpakH9
My trouble is that there's some classes that are indeed being used by Angular, like this one:
.map {
min-height: 200px;
width: 100%;
height: 100%;
a {
color: #text;
}
}
But others are not, like this (you can see on image below that there's nothing related by that definition on browser's styles inspection):
.mapboxgl-ctrl-bottom-left {
display: none !important;
}
What is happening on my case?
I'm following another example that it's working fine. On the component.less file it uses:
#import (reference) "~#eds/vanilla/font/styles";
.dark {
#import "~#eds/vanilla/variables/dark";
#import (multiple) "./map/map";
}
.light {
#import "~#eds/vanilla/variables/light";
#import (multiple) "./map/map";
}
And the map.less file is the same except the by the min-height value.
The example:
You can clearly see that on this example it's using ".light .map {}" to set the style. Different that my case, that converts to ".map[_ng-content-c5] {}" for some reason. I don't have any clue of what this means.
Sorry by being so vague about the problem description. It's simply because I'm don't have enough experience even to name it.
I think I know what the problem is.
If you open your generated css file you see that there is no .mapboxgl-ctrl-bottom-left {
You will instead see something like: .mapboxgl-ctrl-bottom-left[_ngcontent...] {
That's how angular works, it adds some attributes to ensure a style only applies to one component.
You can control if styles are encapsulated or not with ViewEncapsulation
Most likely this happens because the content (in this case the map) is getting rendered with JS after the DOM is loaded and is not handled by angular itself, therefore it doesn't get the attributes.
Without any more information I can't help you any further since I don't know all the details. I don't know exactly which map you are using, maybe there is a tutorial on how to integrate it with angular somehow.

CSS - Target a custom tag with wildcard?

In my Angular application, I have components pages like <app-page-home>, <app-page-login>, <app-page-documentation>, etc. that are mounted when required in my <router-outlet>.
I am trying to target all these components together from a global stylesheet (./src/styles.styl that applies everywhere in the application), but CSS doesn't seem to accept wildcards for custom tags.
I would like to avoid listing my tags one by one and instead, something like app-page-* { border : blue solid 1px; }
app-page-* {
border : blue solid 1px;
}
<app-page-login>Login stuff</app-page-login>
<br>
<app-page-documentation>Documentation</app-page-documentation>
I can't add classes (or can I?) because these component are being dynamically mounted by the router, otherwise I could obviously use something like class="page".
Any idea how to target custom tags with a wild card? Thanks
That's correct, css doesn't have partial type wildcards. Most easy solution is to just group them together, like this;
app-page-login, app-page-documentation { border: 1px solid blue; }
Or apply a class to them;
<app-page-login class="app-page" />
<app-page-documentation class="app-page" />
and target the class;
.app-page { border: 1px solid blue; }
You could do fancy stuff with attribute selectors, but imo for your use case the two solutions above are the most suitable.
-- edit; I see you can't add classes. Use the first solution then.

Use html class to change $primary, $secondary colors in Sass

I am trying to create a Drupal site that allows for multiple color themes on individual pages, rather than the theme as a whole. I have a select menu in Drupal that allows the user to choose which color theme should apply to the page.
I use the value of this field to set the class of the page template. I now want to use this class to change the primary/secondary color value in Sass.
For example, if the user chooses blue, in the HTML template the wrapper is then and I want the Sass to look like this:
$primary: #0000ff;
$secondary: #000066;
And to have these values altered for each theme, green, yellow, etc. Is this possible?
Instead of using the field to change the body class, you could use it to create if/ else statements in the head to call different stylesheets that relate to the colour that has been chosen.
It would require creation of multiple stylesheets, but could be a workaround. No code to supply i'm afraid.
Sam
First of all, you should consider doing this with switching CSS class, but not SASS. Once your site is up and running, the sass has been compiled, and it's pure html and css already, nothing to do with SASS, correct?
So in my opinion, your code might look like this:
SASS:
$theme1-primary: #0000ff;
$theme1-secondary: #000066;
$theme1-primary: #0000ff;
$theme1-secondary: #000066;
.theme1 {
color: $theme1-primary;
background-color: $theme1-secondary;
}
.theme2 {
color: $theme2-primary;
background-color: $theme2-secondary;
}
HTML:
<p class="`if something print theme1 else print theme2`"></p>

Create LESS mixin with class in external file W3.css

I am creating a small personal project mainly with HTML and CSS, but I am new in this and have some problems. I want to use the W3.CSS framework but I don't want to explicitly use it in the html files (like <div class="w3-container">...) because I might want to use something else later and don't want to refactor every file. Googling I learned about less mixins I had the idea of using my own style.less file and from there import w3.css and inherit, for example, .w3-container class for header tags, which I believe cannot be done with only CSS. Anyway, what I am trying to do is:
#import "w3.css";
header {
.w3-container;
}
Both files, "style.less" and "w3.css", are on the same folder and I use the following command to try and compile it:
lessc style.less style.css
Which outputs the error:
NameError: .w3-container is undefined in <path to style.css> on line 3, column 2
I am probably not using less how it's supposed to be. I looked at other questions, for example this one but couldn't do it. I also noticed that my node.js and npm were really outdated: node: v0.12.4, latest: v5.11.0 npm: 2.10.1, latest: 3.8.7 but that wasn't it.
Why doesn't it work?
What other way can I avoid explicitly using classes such as "w3-container"?
Thanks.
Question part 1
With regards to the error:
NameError: .w3-container is undefined in on line 3, column 2
You've used .w3-container as a mixin, but the mixin hasn't been defined. You'd need to define the mixin like so:
#import "w3.css";
.w3-container() {
/*Styles to apply to the mixin would go here*/
}
header {
.w3-container;
}
However it doesn't sound like using a mixin was actually your goal.
Question part 2
With regards to your comment:
What other way can I avoid explicitly using classes such as "w3-container"
LESS compiles down to CSS, so there's no magic that LESS can provide in terms of selectors (such as aliasing W3.css), other than providing some extended functionality to reduce repetition and make your code more maintainable. If you don't want to add new CSS classes, your options are limited to using valid CSS selectors using a higher specificity. The example below is based on path. If w3.css contains:
header {
color: blue;
}
Then to target a header in a section you could use the more specific selector (in LESS):
section {
header {
color: orange;
}
}
This will compile to the CSS:
section header {
color: orange;
}
Question part 3
When you're trying to target an instance of an element of a particular class, it is important to prefix the class with & and include brackets for defining the properties to style like so:
header {
&.w3-container {
color: orange;
}
}
This will compile to the following CSS:
header.w3-container { color: orange; }
If you use .w3-container; by itself, LESS will assume you want to use a mixin here, and will throw the error from Question part 1 since there is no mixin defined with the name .w3-container.
#import (less) "w3.css";
header {
.w3-container;
}