in src/material/form-field/form-field.ts [550:621]
updateOutlineGap() {
const labelEl = this._label ? this._label.nativeElement : null;
const container = this._connectionContainerRef.nativeElement;
const outlineStartSelector = '.mat-form-field-outline-start';
const outlineGapSelector = '.mat-form-field-outline-gap';
// getBoundingClientRect isn't available on the server.
if (this.appearance !== 'outline' || !this._platform.isBrowser) {
return;
}
// If there is no content, set the gap elements to zero.
if (!labelEl || !labelEl.children.length || !labelEl.textContent!.trim()) {
const gapElements = container.querySelectorAll(
`${outlineStartSelector}, ${outlineGapSelector}`,
);
for (let i = 0; i < gapElements.length; i++) {
gapElements[i].style.width = '0';
}
return;
}
// If the element is not present in the DOM, the outline gap will need to be calculated
// the next time it is checked and in the DOM.
if (!this._isAttachedToDOM()) {
this._outlineGapCalculationNeededImmediately = true;
return;
}
let startWidth = 0;
let gapWidth = 0;
const startEls = container.querySelectorAll(outlineStartSelector);
const gapEls = container.querySelectorAll(outlineGapSelector);
if (this._label && this._label.nativeElement.children.length) {
const containerRect = container.getBoundingClientRect();
// If the container's width and height are zero, it means that the element is
// invisible and we can't calculate the outline gap. Mark the element as needing
// to be checked the next time the zone stabilizes. We can't do this immediately
// on the next change detection, because even if the element becomes visible,
// the `ClientRect` won't be reclaculated immediately. We reset the
// `_outlineGapCalculationNeededImmediately` flag some we don't run the checks twice.
if (containerRect.width === 0 && containerRect.height === 0) {
this._outlineGapCalculationNeededOnStable = true;
this._outlineGapCalculationNeededImmediately = false;
return;
}
const containerStart = this._getStartEnd(containerRect);
const labelChildren = labelEl.children;
const labelStart = this._getStartEnd(labelChildren[0].getBoundingClientRect());
let labelWidth = 0;
for (let i = 0; i < labelChildren.length; i++) {
labelWidth += (labelChildren[i] as HTMLElement).offsetWidth;
}
startWidth = Math.abs(labelStart - containerStart) - outlineGapPadding;
gapWidth = labelWidth > 0 ? labelWidth * floatingLabelScale + outlineGapPadding * 2 : 0;
}
for (let i = 0; i < startEls.length; i++) {
startEls[i].style.width = `${startWidth}px`;
}
for (let i = 0; i < gapEls.length; i++) {
gapEls[i].style.width = `${gapWidth}px`;
}
this._outlineGapCalculationNeededOnStable = this._outlineGapCalculationNeededImmediately =
false;
}