Search code examples
htmlcssmedia-queriesangular6angular7

Angular 6/7 css media queries are not applied on grand-child


I'm having some issues on apply media queries (for responsive behavior) on an app that it's using the following component's architecture

  • base components: It uses default encapsulation, there is where external plugins are used, at the moment we're applying, for some cases, PrimeNG external module. The idea is to move these base components to other apps. These are integrated in its own shared module.

  • branding components: It reuses base components, apply custom styles & translate texts, do some specific stuff and it uses native encapsulation (in order to differentiate from base components) but it doesn't apply business logic. These are integrated in its own branding module that imports shared module.

  • business components: It reuses branding components and apply own business logic here (when it's used in several views). These are integrated in its own business module that imports branding module. These components implements default angular encapsulation mode.

Then we have views, that are integrated in its own module & imports business module. It will use branding and or business components, here we're facing some issues regarding to css media queries. These views uses default angular encapsulation mode.

The specific case is that in which we're trying to customize for a specific view an input-field in order to behave correctly for responsive cases (mobile, tablets & desktop on different orientations). In order to do so we're using external plugin angular flex layout (beta 7)

This input-field exist on base component but we're bringing it's branding case. What we want is to change its default width/height set on branding in order to adapt to the div container which will encapsulate it.

This is what we've done so far:

specific view's scss:

// MEDIA QUERIES
:host ::ng-deep {

  @media screen and (min-width: 300px) and (orientation: portrait)  {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width: 95%;
    }
  }

  @media screen and (min-width: 300px) and (orientation: landscape)  {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 2.625);
    }
  }

  @media screen and (min-width: 480px) and (orientation: landscape)  {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 2.9);
    }
  }

  @media screen and (min-width: 640px) and (orientation: portrait)  {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 2);
      height:(16px * 1.6);
    }
  }

  @media screen and (min-width: 640px) and (orientation: landscape)  {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 2.68);
      height:(16px * 1.6);
    }
  }

  @media screen and (min-width: 768px) and (orientation: portrait) {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 3.3);
      height:(16px * 1.6);
    }
  }

  @media screen and (min-width: 768px) and (orientation: landscape) {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 3.5);
      height:(16px * 1.6);
    }
  }

  @media screen and (min-width: 900px) and (orientation: portrait) {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 3.5);
      height:(16px * 1.625);
    }
  }

  @media screen and (min-width: 900px) and (orientation: landscape) {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 1.875);
      height:(16px * 1.625);
    }
  }

  @media screen and (min-width: 1200px) and (orientation: portrait) {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 3.75);
      height:(16px * 1.625);
    }
  }

  @media screen and (min-width: 1200px) and (orientation: landscape) {
    .inputField,
    .inputFieldEditing,
    .inputFieldChanged,
    .inputFieldDisabled {
      width:(80px * 2.5);
      height:(16px * 1.625);
    }
  }
}

Previous custom classes exist & are used in branding input-field component in order to change its UX based on different cases.

branding input-field component template file:

<sh-input-field [id]="id"
                [caption]="caption | translate"
                [(model)]="userInput"
                [placeholder]="placeholder | translate"
                [type]="inputType"
                [color]="color"
                [font-size]="fontsize"
                [isDisabled]="!enabled"
                [style]="{'width': width,
                          'height': height}"
                [status]="status"
                [baseClass]="INPUT_CLASS_ENABLED"
                [extendedClass]="extendedClass"
                [stateClasses]="{
                                  focusedOn: INPUT_CLASS_EDITING,
                                  enabledOn: INPUT_CLASS_ENABLED,
                                  enabledOff: INPUT_CLASS_DISABLED,
                                  valueChanged: INPUT_CLASS_CHANGED
                                }"
              [passwordWeakCaption]="passwordWeakCaption"
              [passwordMediumCaption]="passwordMediumCaption"
              [passwordStrongCaption]="passwordStrongCaption"
              [isPasswordFeedbackShown]="isPasswordFeedbackShown">
</sh-input-field>

branding input-field component scss file:

/* CAPTION */
.uiElemSideCaptionLeft,
.uiElemSideCaptionRight,
.uiElemSideCaptionDisabled {
  position: relative;
  display: inline-block;
  padding-top: 2px;
  text-align: left;
  font-size: 14px;
  -ms-opacity: 1;
  opacity: 1;
  color: #333;
}

.uiElemSideCaptionRight {
  -ms-opacity: 1;
  opacity: 1;
  text-align: right;
}

.uiElemSideCaptionDisabled {
  -ms-opacity: 0.4;
  opacity: 0.4;
}

/* INPUT-FIELD */
.inputField,
.inputFieldEditing,
.inputFieldChanged,
.inputFieldDisabled {
  position: relative;
  display: inline-block;
  height: 16px;
  width: 80px;
  padding: 4px;
  background-color: #dddddd;
  border-width: 1px;
  border-color: #979797;
  border-style: solid;
  font-size: 14px;
  text-align: left;
  color: rgba(0, 0, 0, 1);
  -ms-opacity: 1;
  opacity: 1;
}

.inputFieldEditing {
  -ms-opacity: 1;
  opacity: 1;
  background-color: #eee;
  height: 14px;
  border-width: 2px;
  border-color: #F8E71C;
  color: rgba(0, 0, 0, 1);
  border-style: solid;
}

.inputFieldChanged {
  -ms-opacity: 1;
  opacity: 1;
  background-color: rgba(245, 166, 35, 0.5);
  height: 16px;
  border-width: 1px;
  border-color: #979797;
  color: rgba(0, 0, 0, 1);
  border-style: solid;
}

.inputFieldDisabled {
  -ms-opacity: 0.6;
  opacity: 0.6;
  height: 16px;
  background-color: lightgray;
  border-width: 1px;
  border-color: #979797;
  border-style: solid;
  color: rgba(0, 0, 0, 1);
}

branding input-field component definition:

@Component({
  selector: 'br-input-field',
  templateUrl: './input-field.component.html',
  styleUrls: ['./input-field.component.scss'],
  encapsulation: ViewEncapsulation.Native
})

base input-field component template file:

<div class="sh-input-field-global-container">
  <div class="sh-input-field-label-container" *ngIf="caption !== '' && caption !== undefined && caption !== null">
    <label [for]="id">{{caption}}</label>
  </div>
  <div class="sh-input-field-container" [ngClass]="extendedClass">
    <input *ngIf="controlType !== 'password'"
           [ngClass]="getCssClases('sh-input-field', baseClass)"
           [attr.id]="id"
           [placeholder]="placeholder"
           [disabled]="isDisabled"
           (focus)="InvokeFocus($event)"
           (blur)="InvokeBlur($event)"
           (keyup.enter)="InvokeKeyUpEnterEvent($event)"
           (keyup.escape)="InvokeKeyUpEscapeEvent($event)"
           [(ngModel)]="model"
           [attr.name]="formName"
           [maxLength]="length"
           [type]="controlType"
           [ngStyle]="style"/>
    <input *ngIf="controlType === 'password'"
            [ngClass]="GetCssClases('sh-input-field', baseClass)"
            [attr.id]="id"
            [disabled]="isDisabled"
            (focus)="InvokeFocus($event)"
            (blur)="InvokeBlur($event)"
            (keyup.enter)="InvokeKeyUpEnterEvent($event)"
            (keyup.escape)="InvokeKeyUpEscapeEvent($event)"
            [(ngModel)]="model"
            [attr.name]="formName"
            [maxLength]="length"
            [type]="controlType"
            pPassword
            [promptLabel]="placeholder"
            [weakLabel]="passwordWeakCaption"
            [mediumLabel]="passwordMediumCaption"
            [strongLabel]="passwordStrongCaption"
            [feedback]="isPasswordFeedbackShown"
            [ngStyle]="style"/>
  </div>
</div>

base input-field component definition:

@Component({
  selector: 'sh-input-field',
  templateUrl: './input-field.component.html',
  styleUrls: ['./input-field.component.scss']
})

So what could be wrong here? Are we using :host :ng-deep incorrectly on specific view? We've seen if we apply these media queries directly on branding input-field sass file it works fine (removing :host :ng-deep tag)


Solution

  • Try :host /deep/ instead of :host ::ng-deep as shown below

    :host /deep/ {
        /*your style goes here*/
    }
    

    Or

    Use encapsulation: ViewEncapsulation.Noneinstead ofencapsulation: ViewEncapsulation.Native