I am developing a custom Angular component for a radio button with specific design requirements:
Outer circle size: Fixed at 16px x 16px.Inner circle size (checked state): Fixed at 8px x 8px.The inner circle must always remain perfectly centered inside the outer circle, even when zooming in or out (browser scaling).However, despite using various CSS techniques (e.g., Flexbox, transform: translate), the inner circle slightly shifts out of alignment when zooming or dezooming in the browser. I’m looking for a robust solution to ensure the inner circle stays centered.
Technical Context:Framework: Angular 16.Code: Both HTML and SCSS are provided below.Goal: A CSS solution to ensure a stable alignment of the inner circle regardless of zoom levels.
Here my HTML
<span class="waldo-radio-button" [class.disabled]="disabled" [class.checked]="checked" [class.label-after]="labelPosition === 'after'" [class.label-bottom]="labelPosition === 'bottom'" (click)="onRadioChange($event)"><span class="radio-container"><span class="radio-button" [class.checked]="checked" [class.disabled]="disabled"><span class="inner-circle" *ngIf="checked"></span></span></span><input type="radio" class="mat-radio-input" [id]="id" [name]="name" [value]="value" [checked]="checked" [disabled]="disabled" [required]="required" [attr.aria-describedby]="ariaDescribedby" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledby" /><span class="mat-ripple mat-radio-ripple mat-focus-indicator"><span class="mat-ripple-element mat-radio-persistent-ripple"></span></span><label [for]="id" [style.color]="color"><ng-content></ng-content></label></span>
And my SCSS
.waldo-radio-button { display: inline-flex; align-items: center; /* Vertical alignment */ cursor: pointer; position: relative; gap: 8px;&.disabled { cursor: not-allowed; .radio-button { border-color: var(--neutral-400); .inner-circle { background-color: var(--neutral-400); } } label { color: var(--neutral-400); } }&.checked { .radio-button { border: 2px solid var(--primary-600); .inner-circle { width: 8px; height: 8px; background-color: var(--primary-600); border-radius: 50%; transform: translateZ(0); /* To maintain sharp rendering */ }&:hover { border-color: var(--primary-700); }&:active { border-color: var(--primary-800); } } } .radio-container { position: relative; width: 16px; /* Outer circle size */ height: 16px; display: flex; justify-content: center; /* Horizontal centering */ align-items: center; /* Vertical centering */ } .radio-button { width: 16px; height: 16px; border: 2px solid var(--neutral-500); /* Default border color */ border-radius: 50%; /* Perfect circle */ display: flex; justify-content: center; align-items: center; /* Center the inner circle */ transition: border-color 0.2s ease; .inner-circle { width: 8px; /* Inner circle size */ height: 8px; background-color: transparent; /* Initially invisible */ border-radius: 50%; /* Perfect circle */ transform: scale(0); /* Hidden by default */ transition: transform 0.2s ease, background-color 0.2s ease; } } input[type='radio'] { position: absolute; opacity: 0; pointer-events: none; } label { color: var(--neutral-700); cursor: pointer; display: inline-block; }}
What I’ve Tried:Flexbox: Used in .radio-container and .radio-button to center the inner circle.Transformations: Applied transform: scale and translateZ(0) to stabilize rendering.Fixed Sizes: Set fixed dimensions for both the outer circle (16px) and the inner circle (8px).