Angular CSS class names collide with other components after Material Theming - css

Hey there I've read many things about the style scopes for example https://angular.io/guide/component-styles. And somehow the point
Class names and selectors are local to the component and don't collide
with classes and selectors used elsewhere in the application.
does not work for me.
I have a header-component with the css class profileImage. Then there's also the class profileImage in my user-component. I'm not using any custom encapsulation for any component. But still it's buggy now because the class profileImage of the user-component also uses the one of the header-component and only overrides the elements defined in both. So for example position: absolute; gets inherited but it should not.
.profileImage[_ngcontent-bkm-c17] { //user-component
max-width: 34px;
max-height: 34px;
width: auto;
height: auto;
margin: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.profileImage { //header-component
border-radius: 50%;
position: absolute;
max-width: 54px;
max-height: 54px;
width: auto;
height: auto;
margin: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
This happend after using angular theming. To explain what exactly is forcing this problem:
I got a component-themes.scss:
#import "./app/header/header.component";
#mixin component-themes($theme) {
#include tile-theme($theme);
}
It's included in my material-themes.scss:
#include angular-material-theme($theme);
#include component-themes($theme);
.dark-theme {
color: $light-primary-text;
$dark-primary: mat-palette($mat-grey, 700, 300, 900);
$dark-accent: mat-palette($mat-blue-grey, 400);
$dark-warn: mat-palette($mat-red, 500);
$dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
#include angular-material-theme($dark-theme);
#include component-themes($dark-theme);
}
And this is used in the basic styles.scss.
How can I prevent the described behavior while using component-themes?
The following code is for a mat-menu not a tile. I haven't renamed it yet because it's a copy of a tutorial.
header-component.scss (requested):
#import "~#angular/material/theming";
#mixin tile-theme($theme) {
$primary: map-get($theme, primary);
$background: map-get($theme, background);
$background-color: mat-color($background, card);
.tile {
background-color: mat-color($primary);
}
}
.toolbar-spacer {
flex: 1 1 auto;
}
// verantwortlich für das Layout der Toolbar
.startpage:hover {
opacity: 0.6;
}
.mat-toolbar {
height: 7vh;
}
div {
overflow: inherit;
}
.language-buttons {
padding: 0 25px;
margin-right: 32px;
}
.language-buttons-login {
padding: 0 20px;
}
.navigate-buttons {
padding: 0 12px;
}
.mat-fab.mat-accent {
background: #3f51b5;
}
::ng-deep .mat-menu-panel {
position: relative;
top: 5px;
right: -16px;
}
.mat-button,
.mat-flat-button,
.mat-icon-button,
.mat-stroked-button {
min-width: 1px;
}
.imageContainer {
width: 54px;
height: 54px;
right: 20px;
position: absolute;
}
.profileImage {
border-radius: 50%;
position: absolute;
max-width: 54px;
max-height: 54px;
width: auto;
height: auto;
margin: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.font-awesome {
margin-right: 19px;
}
// ::ng-deep .accent-tooltip {
// background-color: mat-color($accentPalette);
// }

You are importing your "./app/header/header.component"; inside the component-theme.scss. This leads to the result that all styles from header.component will be global, because you are using the material-themes.scss in your global styles.scss.
So all styles you defined in header.component.scss will be loaded global, without that the angular compiler adds special attributes to ensure encapsulation. This leads to the result that other components, with the same classes will inherit all properties.
UPDATE:
Original answer proposed to simply remove the #import header.component statement, but after OP added the header.component implementation it was obvious that this would not be sufficient.
To solve this the best solution would be to replace the #import rule with the #use rule. But as this feature is currently only included in DartSass and only since version 1.23.0, another solution is to remove the mixin definition from the header.component.scss file and move it directly to the component-theme.scss, and remove the #import rule.

Related

How do I add a logic to control CSS "After" Pseudo-elements?

Currently I have this html in pug and vue code which is working fine. Basically the arrow width is dynamic.
.abc--step-bar: .abc--step-bar-color(:style="`width: ${progressBar.width}`")
.row
.col(v-for="(item, i) in progressItems")
.abc--step-item(:class="{ 'is__done': progressBar.index > i, 'is__current': progressBar.index === i }")
span.abc--step-dot
This is my css using SCSS
.abc--step-bar {
position: absolute;
top: 0;
left: 16.7%;
right: 16.7%;
height: 3px;
background: #e8e8e8;
}
.abc--step-bar-color {
background: #28A745;
position: absolute;
top: 0; bottom: 0; left: 0;
&:after {
color: #28A745;
content: url("../../assets/images/arrow.png");;
display: inline-block !important;
width: 0;
height: 0;
position: absolute;
right: 6px;
top: -6px;
}
}
.abc--step-dot {
display: inline-block;
width: 15px;
border-radius: 50%;
height: 15px;
background: #e8e8e8;
border: 5px solid #e8e8e8;
position: relative;
top: -7px;
.is__done &,
.is__current & {
border: 5px solid #28A745;
//background: #28A745;
}
}
I use the image for the arrow head.
I do not know how I can hide the arrow head with certain logic using Vuejs. i.e. when the progressBar.index equals 1. My arrow head is at after Pseudo-element.
I tried to put the similar example in my codepen.
https://codepen.io/steve-ngai-chee-weng/pen/xxXmRer
Use a Vue-conditional CSS class hide-arrow that hides it. JS cannot access pseudo elements directly.
.abc--step-bar-color.hide-arrow::after { content: ""; }
Please note that :after is very old CSS 2.1 syntax. In CSS 3 pseudo elements must be prefixed with ::.

Nested Derived CSS Variable [duplicate]

This question already has answers here:
CSS scoped custom property ignored when used to calculate variable in outer scope
(2 answers)
Closed 1 year ago.
I have the following CSS
:root {
--primary: #1776BF;
--header-background-color: var(--primary);
}
header {
--primary: #EA5742;
}
header {
position: fixed;
top: 0;
height: 60px;
left: 0;
right: 0;
background-color: var(--header-background-color); //Expecting it to be #EA5742 but it is still #1776BF
}
As far as I have researched, CSS Variable is not meant to be for this type of case. But still, Is there any way to achieve the expected behavior as I mentioned in the comment line of the above code snippet.
If you want --header-background-color to update is value for header, then you'll have to redeclare that variable too. Just try re-adding --header-background-color: var(--primary); below your second --primary declaration and it will work.
:root {
--primary: #1776BF;
--header-background-color: var(--primary);
}
header {
--primary: #EA5742;
--header-background-color: var(--primary); /* you need to redeclare this variable so that it takes the newly assigned primary value */
}
header {
position: fixed;
top: 0;
height: 60px;
left: 0;
right: 0;
background-color: var(--header-background-color);
}
div { /* this is just an example so you can check the global variable works well too */
position: fixed;
top: 60px;
height: 60px;
left: 0;
right: 0;
background-color: var(--header-background-color);
}
<header>Test</header>
<div>Test</div>
You're right, as var(--xxx) is just replaced by it's value at this time. But why don't you simplify your problematic this way ?
:root {
--primary: #1776BF;
}
body {
background-color: var(--primary);
}
header, anotherelement, yetanotherelement, .aclass {
--primary: #EA5742;
}
header {
position: fixed;
top: 0;
height: 60px;
left: 0;
right: 0;
background-color: var(--primary);
}
<header>test</header>

Can't get a fullscreen modal using NgbModal when passing content as a component

I am using Bootstrap widgets and am attempting to create a full screen modal (header sticks on top, footer on bottom, and body scrolls in the middle). I can easily do this with some simple html as outlined here:
https://www.codeply.com/go/DLPXHfEIiS/bootstrap-4-full-screen-modal
However, once I start getting more complex and want to call my own component as the content then it no longer works. The component nests one level down from the modal-content and I believe this is what is breaking the flow. I am attempting to follow the instructions outlined here:
https://ng-bootstrap.github.io/#/components/modal/examples#component
Even in this above example you can inspect it and see the component is nested within the modal-content div.
The effect (when trying to go full screen using the method in the first link above) is that the modal, modal-dialog, and modal-contend all DO go full screen. However, the nested component within the modal component sizes to content despite my attempts to style it to behave.
What obvious thing am I missing here? Thanks in advance and happy Friday.
::EDIT TO OVERRIDE LIMITATIONS IN COMMENTS::
CSS
.gr-modal-full .modal-dialog {
min-width: 100%;
margin: 0;
}
.gr-modal-full .modal-content {
min-height: 100vh;
}
.TS CALLING THE COMPONENT
const journalPopup = this.modalService.open(
JournalPopupComponent,
{windowClass: 'gr-modal-full', backdrop: false});
journalPopup.componentInstance.journal = this.journal;
COMPONENT
import {Component, Input, OnInit} from '#angular/core';
import {NgbActiveModal} from '#ng-bootstrap/ng-bootstrap';
import {HttpClient} from '#angular/common/http';
#Component( {
selector: `
<div class="modal-header"></div>
<div class="modal-body"></div>
<div class="modal-footer"></div>
`,
templateUrl: './journal.popup.component.html',
styleUrls: ['./journal.popup.component.scss']
})
export class JournalPopupComponent implements OnInit {
#Input() journal: any;
constructor(public modal: NgbActiveModal) {}
ngOnInit(): void {
}
}
Have the answer by throwing away the above code and going more old-school. I just used CSS and made the components absolute. As long as the heights of my header and footer don't need to change (which I can control) this does the trick.
Props to John Paul Hennessy and his codepen for giving me the kick I needed at this link: https://codepen.io/yewnork/pen/Kpaqeq
.gr-modal-full .modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
}
.gr-modal-full .modal-dialog {
position: fixed;
margin: 0;
min-width: 100%;
height: 100%;
padding: 0;
}
.gr-modal-full .modal-content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
border-radius: 0;
}
.gr-modal-full .modal-header {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 80px;
padding: 10px;
border-radius: 0;
//background: #6598d9;
}
.gr-modal-full .modal-title {
font-weight: 300;
font-size: 2em;
color: #fff;
line-height: 30px;
}
.gr-modal-full .modal-body {
position: absolute;
top: 81px;
bottom: 61px;
width: 100%;
overflow: auto;
}
.gr-modal-full .modal-footer {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 60px;
padding: 10px;
border-radius: 0;
//background: #f1f3f5;
}

Root class is not read by SASS, only those with ampersand are

I have a sass/css class with an ampersand, this is used in conjunction with VueJS. What I was wondering is that the CSS attribute assigned on the ampersand is working but the root element itself isn't detected by the browser.
<style lang="scss" scoped>
.curved-input {
border-radius: 5px;
height: 50px;
margin-right: 1rem;
&__lg {
width: 300px;
}
&__sm {
width: 150px;
}
}
</style>
Here's the explanation, the browser seem to detect the width: 300px or width: 150px but not the border-radius, height, margin-right.
<input name="city" class="curved-input__lg" type="text" placeholder="Palau Ujong, Singapore"/>
The textbox width changed but other attributes are not read by the browser when you look at them on the browser tools. Am I missing something here?
My goal is not to code it as class="curved-input curved-input__lg but rather only use curved-input__lg or curved-input__sm while inheriting the parent attributes (curved-input).
You could use #extend to avoid adding additional classes to your markup or (some) duplicate code, if that is your goal.
.curved-input {
border-radius: 5px;
height: 50px;
margin-right: 1rem;
}
.curved-input {
&__lg {
#extend .curved-input;
width: 300px;
}
&__sm {
#extend .curved-input;
width: 150px;
}
}
Which would generate the following CSS
.curved-input,
.curved-input__sm,
.curved-input__lg {
border-radius: 5px;
height: 50px;
margin-right: 1rem;
}
.curved-input__lg {
width: 300px;
}
.curved-input__sm {
width: 150px;
}
This is because you have to declare the curved-input class as well. So your class attribute will look like class="curved-input curved-input__lg".
If you'd write out your CSS in full you'll get something like this:
.curved-input {
border-radius: 5px;
height: 50px;
margin-right: 1rem;
}
.curved-input__lg {
width: 300px;
}
.curved-input__sm {
width: 150px;
}
With this in mind you'll see that you have to add the class curved-input as well.
Well if you want to write it like that, try to change the first line to:
[class*="curved-input"]

How can I make a full width videojs v5 progress bar?

I would like to change the videojs v5 controls layout in order to make a full width progress bar, on top of the vjs-control-bar area, similar to the pre-v5 player skin.
Here is the v5 skin:
And here is the pre-v5 skin. Notice the full width progress bar:
How should I proceed? Is it necessary to modify the component structure tree within the ProgressControl component or can it be done using CSS only, with the existing ProgressControl component?
I noticed that I can put it on top by changing the vjs-progress-control display CSS property from flex to block, initial or inline but I can't set the width to 100% (other ProgressControl components width are still considered). I assume it is because the vjs-progress-control is still in the flex flow of the container.
EDIT
I made some progress. I can achieve the desired effect by using the following CSS:
.vjs-progress-control {
position: absolute;
bottom: 26px; /* The height of the ControlBar minus 4px. */
left: 0;
right: 0;
width: 100%;
height: 10px; /* the height must be reduced from 30 to 10px in order to allow the buttons below (e.g. play) to be pushed */
}
.vjs-progress-holder {/* needed to have a real 100% width display. */
margin-left: 0px;
margin-right: 0px;
}
Unless one of you find a way to make it better, I will post this edit as accepted answer when it will be allowed.
DEMO
.vjs-fluid {
overflow: hidden;
}
.vjs-control-bar {
display: block;
}
.vjs-control {
position: absolute;
}
.vjs-progress-control {
bottom: 28px; left: 0;
height: 10px;
width: 100%;
}
.vjs-progress-holder {
position: absolute;
left: 0; margin: 0;
height: 8px; width: 100%;
}
.vjs-play-progress,
.vjs-load-progress {
height: 8px;
}
.vjs-play-progress:before {
font-size: 12px; top: -2px;
text-shadow: 0 0 2px black
}
.vjs-current-time {
display: block;
left: 35px;
}
.vjs-time-divider {
position: absolute;
display: block;
left: 70px;
}
.vjs-remaining-time {
display: none;
}
.vjs-duration {
display: block;
left: 70px;
}
.vjs-volume-menu-button {
position: absolute;
bottom: 0; right: 55px;
}
.vjs-playback-rate {
position: absolute;
bottom: 0; right: 28px;
}
.vjs-fullscreen-control {
position: absolute;
bottom: 0; right: 0;
}
There's still need to style the subtitles, captions and chapter buttons
.video-js .vjs-progress-control {
position:absolute;
width: 100%;
top:-.3em;
height:3px;
/* deal with resulting gap between progress control and control bar that
is the result of the attempt to keep things "clickable" on the controls */
background-color: #2B333F;
background-color: rgba(43, 51, 63, 0.7);
}
.video-js .vjs-progress-holder {
position:absolute;
margin:0px;
top:0%;
width:100%;
}
This seemed to get rid of the problems I had across other browsers with the :hover styling inherited from video.js. More masterful css developers might be able to make the expansion a bottom-to-top expansion, negating the need for the fancy footwork around the position of the progress control and the color.
Here is a minimal custom skin (in scss) that shows a full-width progress bar above the rest of the controls. This works with video.js 5.19.2
.video-js.vjs-custom-skin {
.vjs-custom-control-spacer {
display: flex;
flex: 1 1 auto;
}
.vjs-time-divider {
display: inherit;
}
.vjs-current-time {
margin-left: 1em;
}
.vjs-current-time, .vjs-duration {
display: inherit;
padding: 0;
}
.vjs-remaining-time {
display: none;
}
.vjs-play-progress:before {
display: none;
}
.vjs-progress-control {
position: absolute;
left: 0;
right: 0;
width: 100%;
height: .5em;
top: -.5em;
&:hover {
height: 1.5em;
top: -1.5em;
}
}
.vjs-progress-holder {
margin: 0;
height: 100%;
}
}

Resources