Edit - Following comments and thinking this through a bit, I have added the options as I see them to the bottom of this question.
Original Question
I have an Angular component (down below, html and scss file, nothing really in the component class for brevity). Lets call it "h5-underliner" and used like:
<app-h5-underliner>My Title</app-h5-underliner>
`
h5 {
margin-bottom: 1.8rem;
padding-bottom: 2rem;
position: relative;
}
h5:after {
content: "";
position: absolute;
bottom: 0;
left: 0.1rem;
height: 0.2rem;
width: 6rem;
background: $colour-apg-accent;
}
<h5 [class]="colourThemeName">
<ng-content></ng-content>
</h5>
`
Now say for example I want an "h2 underliner"
<app-h2-underliner>My Heading 2 Title</app-h2-underliner>
Which picks up the apps h2 styling.
How can I aceive this without duplicating all the css (which would end up something like the below:)
`
h2 {
margin-bottom: 1.8rem;
padding-bottom: 2rem;
position: relative;
}
h2:after {
content: "";
position: absolute;
bottom: 0;
left: 0.1rem;
height: 0.2rem;
width: 6rem;
background: $colour-apg-accent;
}
`
It's not a huge example, but I dont like the repetition. I thought about a directive, but the pseudo selector after kills that idea (as far as I am aware).
Note there is a little bit of extra going on as the caller can choose a colour, but that just means more repetition between very similar components (i.e. only the h5 and h2 tags differ).
So options:
Option 1 - The mess abouve with <h2-underliner>Mt Title Text<\h2-underliner> and <h5-underliner>Mt Title Text<\h5-underliner> - bad for several reaons.
Option 2 - Global style for the css that can be applied to tags as required (.my-underliner) OR we make the decision that all h5 and h2 titles have this style. On one hand we set typography globally with mat custom typography - but it doesn't seem right to start adding global css for general css.
Option 3 - A component that follows the same pattern as material form field/content projection: <app-underliner><h5>My title text</h5></app-underliner> - in this case we contain the common style to one component and still have the freedom to use it with different headings.
Styles follow hierarchical override in angular. So if both of those components that you refer lets call them B, C are children of component A, then you can put those styles on component A.
Then B, C will inherit those styles from parent A
They don't even have to be direct children of A to inherit styles of A.
So in a structure like
A - D - C
|_ B
D, C , B will inherit styles declared in component A
Related
I am using PrimeNG OverlayPanel to be displayed in dropdown click but I have a problem to move default left arrow to right position. I tried everything that was in my mind but I am out of ideas.
Can you please give me some new idea for resolving this issue?
code example: https://stackblitz.com/edit/primeng-overlaypanel-demo
dropdown arrow image
Your goal is override deeply incapsulated CSS. One of the possible sollution is to add an id to overlay-panel and then ovverride the desired element(in our case this is before and after pseudo-elements of a div with the p-overlay class
html:
<p-overlayPanel #op [showCloseIcon]="true" id='hello'[style]="{width: '450px'}">
css:
:host ::ng-deep #hello .p-overlaypanel::before,
:host ::ng-deep #hello .p-overlaypanel::after
{
left: 80%;
}
left: 80% is for example.
stackblitz
Add this to style.css:
.p-overlaypanel:after, .p-overlaypanel:before{
left: unset !important;
right: 1.25rem !important;
}
Now the arrow is on the right side opposite of initial.
Additional info: avoid using :host ::ng-deep as it is deprecated.. use the style.css file instead!
.mybutton .p-overlaypanel:after, .mybutton .p-overlaypanel:before {
bottom: 100%;
content: " ";
height: 0;
right: 1.25rem; //<---
pointer-events: none;
position: absolute;
width: 0;
}
is the place but the question is;
how you wish to handle button positioning on page. If button near left,right,bottom border then you should handle arrow position. by this variable.
Convert your entire Angular project to Scss. The reason is that View styles do not go deep. Scss in root does go deep and is worth it long term to stop using just CSS in Angular projects. I wrote an article on this.
For p-overlaypanel
:before and :after are the attributes you should catch for this to work
body .p-overlaypanel:before {
left: calc(100% - 17px);
}
body .p-overlaypanel:after {
left: calc(100% - 17px);
}
You can override it in global stylesheet ie style.scss
by wrapping the elements with a custom class. This will provide more specificity.
.your-class {
.p-overlaypanel:before {
left: calc(100% - 17px);
}
.p-overlaypanel:after {
left: calc(100% - 17px);
}
}
I am using polymer 3 and lit-element(2.2.1). The version of mwc-textfield is 0.13.0. I have read the documentations related to this version.In this documentation, I have found that we can add mixin for height. I had tried several ways but did not succeed. May be the syntax I am using is wrong. I want to decrease the height of my text field. This is my text field
<mwc-textfield id="textBox" .type="text" .value=${this.title} .placeholder='' minLength="10" maxLength="256"></mwc-textfield>
and my css
#textBox{
text-transform: none;
--mdc-theme-primary: transparent;
--mdc-text-field-fill-color: #fff;
--mdc-text-field-hover-line-color: #f5f5f5;
--mwc-text-width: 100%;
width:100%;
}
The default css applied is
:host(:not([disabled])) .mdc-text-field:not(.mdc-text-field--outlined) {
background-color: transparent;
}
.mdc-text-field:not(.mdc-text-field--disabled) {
background-color: rgb(245, 245, 245);
}
.mdc-text-field {
display: flex;
width: 100%;
}
.mdc-text-field {
height: 56px;
display: inline-flex;
position: relative;
box-sizing: border-box;
will-change: opacity, transform, color;
border-radius: 4px 4px 0px 0px;
overflow: hidden;
}
.mdc-text-field {
--mdc-ripple-fg-size: 0;
--mdc-ripple-left: 0;
--mdc-ripple-top: 0;
--mdc-ripple-fg-scale: 1;
--mdc-ripple-fg-translate-end: 0;
--mdc-ripple-fg-translate-start: 0;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
user agent stylesheet
label {
cursor: default;
}
<style>
#textfield {
width: var(--text-field-width,80%);
height: 100%;
position: absolute;
left: 0;
top: -12px;
text-transform: capitalize;
--mwc-text-width: 100%;
}
<style>
mwc-textfield {
--mdc-theme-primary: transparent;
--mdc-text-field-ink-color: black;
--mdc-text-field-fill-color: transparent;
--mdc-text-field-disabled-fill-color: transparent;
}
The default height applied to the text field is 56px. What I have tried is
#textbox.mdc-text-field--height{
height:45px;
}
and
#textbox.mdc-text-field--height('45px');
and also added mixin in the node modules file as height:var(--mdc-text-field-height,56px);
and used in css as
#textBox{
--mdc-text-field-height:45px;
}
Any help would be greatly appreciated! Thanks in advance.
Material design components vs Material web components
I have read the documentations related to this version. In this documentation, I have found that we can add mixin for height.
The first thing to note here is that there are two different libraries of material components: the one you are referring to is MDC (Material Design Components, distributed on npm as #material/<component>) which is a SASS+JS implementation of Material components. The other one is MWC (Material Web Components, distributed as #material/mwc-<component>), a collection of actual WebComponents based on the former library. So keep in mind that the documentation refers to the MDC counterpart of the MWC component you're actually using (<mwc-textfield>).
Styling from the outside
What you're trying to do here
#textbox.mdc-text-field--height {
height: 45px;
}
doesn't work mainly because selecting inside a custom element's shadow root is not possible (at least, not anymore); also, the element responsible for the height is the <label>, whose class is .mdc-text-field.
The querySelector way
The quickest way to change the height that comes to my mind is this:
import { LitElement, html, property, customElement, css, query } from 'lit-element';
import '#material/mwc-textfield';
#customElement('my-component')
export class MyComponent extends LitElement {
// Select the text field
#query('mwc-textfield') textField;
async firstUpdated() {
// Wait for its dom to be ready
await this.textField.updateComplete;
// Programmatically select the label
// and change the height
this.textField
.shadowRoot
.querySelector('.mdc-text-field')
.style
.height = '45px';
}
render() {
return html`<mwc-textfield></mwc-textfield>`;
}
}
however I would really not recommend it: performance and elegance aside, it'll probably break some of mwc-textfield features such as the floating label.
The extension way
You can also enforce the height by extending TextField and overriding the styles:
import {LitElement, html, customElement, css} from 'lit-element';
import {TextField} from '#material/mwc-textfield/mwc-textfield';
#customElement('my-textfield')
export class MyTextfield extends TextField {
static styles = [TextField.styles, css`
.mdc-text-field {
height: 45px;
}
`];
}
// Then use <my-textfield> instead of <mwc-textfield>
but again, like the above, use at your own risk...
Using the mixin
I guess for now the only way of using the height mixin is building a customised version of TextField which more or less goes like this:
clone the mwc repo (yeah, it's a monorepo so you get all the other components as well, but I'm pretty sure you can delete all the ones not imported by mwc-textfield)
npm install
in packages/mwc-textfield/src/mwc-textfield.scss use the mixin:
#include mixins.height(45px);
probably around here
npm run build
copy the mwc-textfield folder and paste it in your project (delete the source files, npm pack may be handy for this), then change the imports from #material/mwc-textfield to ./path/to/custom-textfield
Certainly too much work for changing a height... The good news is MWC is still in development and it cannot be excluded that they'll add a CSS custom property or some other way to customise the height. Also, the new density concepts are being implemented in MWC (sadly not yet in TextField), which could be just what you need.
There is also an open issue about this, let's see what they say
I've created a Custom Form Field Control for Angular 8 compatible with Reactive Forms and Angular Material. However, it being a simplified Rich-Text Editor, it has a header with various buttons with actions for the user.
How can I move the Placeholder label below the header of my input control to the actual textarea?
Current placeholder label placement
Well, since nobody really responded to my question, I'll post my own solution to this problem, one cruder (Solution 2) and one I deem proper (Solution 2, though to me it appears otherwise).
Edit: Solution 2: Proper approach
Well, I tried to make my code slightly more-configurable, hence I made one little mistake when changing code - I changed one variable to static, a variable used to declare the ID MatFormField uses in a class definition inside itself which we can use to customize the look of our component.
Namely controlType. Using this variable, we can identify when our component is in-use by direct class name following naming convention mat-form-field-type-<controlType>. So, since my controlType = "app-text-editor", I can use it like this:
.mat-form-field-type-app-text-editor:not(.mat-form-field-should-float) .mat-form-field-label-wrapper > .mat-form-field-label {
margin-top: 2.5rem;
padding: .5em;
}
Original: Solution 1: Hacky-approach
What I did was change my component to encapsulation: ViewEncapsulation.None, used the selector of my component inside css as my main identifier (in my case: app-text-editor) and then used CSS Sibling selector to select the floating label and placeholder to set offset for my TextEditor header and reset it back to default once the label is floating. The resulting CSS looks like this:
app-text-editor {
// Styling for actual TextEditor
&.floating ~ .mat-form-field-label-wrapper > .mat-form-field-label {
margin-top: initial;
padding: initial;
}
& ~ .mat-form-field-label-wrapper > .mat-form-field-label {
margin-top: 2.5rem;
padding: .5em; // Used to properly align the content inside my contenteditable
}
Or as pure CSS would look like:
app-text-editor.floating ~ .mat-form-field-label-wrapper > .mat-form-field-label {
margin-top: initial;
padding: initial;
}
app-text-editor ~ .mat-form-field-label-wrapper > .mat-form-field-label {
margin-top: 2.5rem;
padding: .5em; /* Used to properly align the content inside my contenteditable */
}
Weirdly enough, even the animation transition looks smooth despite me using such a hacky-approach for repositioning it.
If you don't mind using advanced CSS selector (Can I Use: Advanced CSS3 selectors), the solution can be even cleaner:
SCSS:
app-text-editor {
// Styling for the actual TextEditor
&:not(.floating) ~ .mat-form-field-label-wrapper > .mat-form-field-label {
margin-top: 2.5rem;
padding: .5em; // Used to properly align the content inside my contenteditable
}
Pure CSS:
app-text-editor:not(.floating) ~ .mat-form-field-label-wrapper > .mat-form-field-label {
margin-top: 2.5rem;
padding: .5em; /* Used to properly align the content inside my contenteditable */
}
Very new to Scss/Sass Elsewhere in my mod.scss file, have coded the style of Ul > li that I reuse quite frequently. However, in another mod.scss file, I need a change this code for a single particular instance.
Is it possible to essentially create an if-like statement that says: "If a UL/LI tag appears UNDER the .content-section class, take on behaviors X,Y and z"?
.content-section
{
margin: 40px 0px;
& .siteTitleText
{
margin-bottom: 50px;
}
& .headers
{
margin-bottom: 30px;
}
img
{
margin: 30px 0px;
}
*ul*
}
HTML:
<div class="content-section vendors">
<p class="headers">Modules, partials, and vendor</p>
<p class="bodyText">As you can see this divides my project into three basic types of files. Modules, partials, and vendored stylesheets.</p>
<ul>
<li class="bodyText">The modules directory is reserved for Sass code that doesn't cause Sass to actually output CSS. Things like mixin declarations, functions, and variables.</li>
<li class="bodyText">The partials directory is where the meat of my CSS is constructed. A lot of folks like to break their stylesheets into header, content, sidebar, and footer components (and a few others). As I'm more of a SMACSS guy myself, I like to break things down into much finer categories (typography, buttons, textboxes, selectboxes, etc…).</li>
<li class="bodyText"></li>
</ul>
</div>
Use the + in your code to select the next match below your closing tag.
Simply nest the tags if you wish to select the child tag inside your .content-section.
Reference: w3 documentation
.content-section {
margin: 40px 0px;
& .siteTitleText {
margin-bottom: 50px;
}
& .headers {
margin-bottom: 30px;
}
img {
margin: 30px 0px;
}
ul, li { // If .content-section has a child named ul or li, do this:
margin: 100px;
}
}
I'm just curious to know if it is possible to have specific stylings based on the name of of a class.
For example, Bootstrap 4 has a helper class for margins and padding like:
<div class="m-t-1 p-a-0"></div>
This gives the div 1em of margin to the top, and removes padding from all sides.
I am sure they have pre-styled this class in their CSS to achieve this.
But I am curious if there is a way to use the class as a variable.
for example:
<div class="fs-x"></div>
where x can be any number, this class would then give the styling the font-size: x to the div.
Is this possible to do?
Thanks.
You can use a CSS pre-processor such as SASS or LESS to achieve this however it generates static classes within a specified range below is an example from the SASS documentation:
$class-slug: for !default
#for $i from 1 through 4
.#{$class-slug}-#{$i}
width: 60px + $i
Which emits this CSS:
.for-1 {
width: 61px;
}
.for-2 {
width: 62px;
}
.for-3 {
width: 63px;
}
.for-4 {
width: 64px;
}
All CSS classes must be explicitly defined. So every variation if X would need to exist in a .css file
you can use constant in css for example
$x = 10px;
img{
margin-bottom : $x;
}
but however you can declare variables with this way
:root {
--color-principal: #06c;
}
#foo h1 {
color: var(--color-principal);
}