fix(link): improve ionic theme links styles and dev experience (#30375)

Issue number: internal

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->


## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Adjust link styles to match latest Figma UI and tokens.
- For default link, make it work without the need of adding a class.
- Change `ionic` to `ion` on the class names.
- Adjusted tests to reflect the changes.

## Does this introduce a breaking change?

- [] Yes
- [x] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer
for more information.
-->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

- [Ionic
Link](https://ionic-framework-git-rou-11850-ionic1.vercel.app/src/css/test/link/basic?ionic:theme=ionic)

---------

Co-authored-by: ionitron <hi@ionicframework.com>
This commit is contained in:
Bernardo Cardoso
2025-04-30 16:22:59 +01:00
committed by GitHub
parent d3165fc229
commit b2f6b8c67e
33 changed files with 58 additions and 73 deletions

View File

@ -42,7 +42,7 @@
Title
<p>With list + link</p>
</ion-label>
<a class="ionic-link" href="#">Clear</a>
<a href="#">Clear</a>
</ion-list-header>
<ion-item lines="none">
<ion-label color="primary">List item</ion-label>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -3,6 +3,8 @@
// Link: Shared Styles (Standalone & Underline)
// -------------------------------------------------------------------------------
@mixin link-shared {
@include globals.typography(globals.$ion-body-action-sm);
display: inline-flex;
align-items: center;
@ -11,8 +13,6 @@
transition: color globals.$ion-transition-time-200 ease-in-out;
font-weight: globals.$ion-font-weight-regular;
text-decoration-color: inherit;
text-underline-offset: globals.$ion-scale-050;
@ -25,6 +25,37 @@
&:visited {
color: globals.$ion-text-link-visited;
}
// Link: Focus
// -------------------------------------------------------------------------------
&:focus,
&.ion-focused {
@include globals.focused-state();
border-radius: globals.$ion-border-radius-100;
}
// Link: Active
// -------------------------------------------------------------------------------
&:active,
&.ion-activated {
color: globals.$ion-text-link-press;
text-decoration: underline;
}
// Link: Hover
// -------------------------------------------------------------------------------
@media (any-hover: hover) {
&:hover {
color: globals.$ion-text-link-press;
text-decoration: underline;
}
}
}
// Link: Standalone
@ -36,39 +67,10 @@
text-decoration: none;
@include link-shared;
// Link: Standalone - Hover
// -------------------------------------------------------------------------------
@media (any-hover: hover) {
&:hover {
text-decoration: underline;
}
}
// Link: Standalone - Focus
// -------------------------------------------------------------------------------
&:focus,
&.ion-focused {
@include globals.focused-state(null, null, globals.$ion-text-link-default);
text-decoration: underline;
}
// Link: Standalone - Active
// -------------------------------------------------------------------------------
&:active,
&.ion-activated {
color: globals.$ion-text-link-press;
text-decoration: underline;
}
}
a.ionic-link,
:not(a).ionic-link a {
a,
:not(a).ion-link a {
@include ionic-link;
}
@ -76,41 +78,24 @@ a.ionic-link,
// -------------------------------------------------------------------------------
@mixin ionic-link-underline {
color: currentColor;
text-decoration: underline;
color: globals.$ion-text-default;
@include link-shared;
// Link: Underline - Hover
// -------------------------------------------------------------------------------
text-decoration: underline;
@media (any-hover: hover) {
&:hover {
color: globals.$ion-text-link-press;
}
}
// Link: Underline - Focus
// Link: Focus
// -------------------------------------------------------------------------------
&:focus,
&.ion-focused {
@include globals.focused-state(null, null, globals.$ion-text-link-default);
color: globals.$ion-text-default;
text-decoration: none;
}
// Link: Underline - Active
// -------------------------------------------------------------------------------
&:active,
&.ion-activated {
color: globals.$ion-text-link-press;
}
}
a.ionic-link-underline,
:not(a).ionic-link-underline a {
a.ion-link-underline,
:not(a).ion-link-underline a {
@include ionic-link-underline;
}

View File

@ -28,45 +28,45 @@
</ion-header>
<ion-content class="ionic-padding-space-m">
<h3>Standalone (.ionic-link)</h3>
<h3>Standalone (.ion-link)</h3>
<div class="links" id="standalone">
<div><a class="ionic-link" href="#">Link - Default</a></div>
<div><a class="ionic-link ion-activated" href="#">Link - Active</a></div>
<div><a class="ionic-link ion-focused" href="#">Link - Focused</a></div>
<div><a class="ionic-link" href="">Link - Visited</a></div>
<div><a href="#test-visited-link">Link - Default</a></div>
<div><a class="ion-activated" href="#">Link - Active</a></div>
<div><a class="ion-focused" href="#">Link - Focused</a></div>
<div><a href="">Link - Visited</a></div>
<div>
<a class="ionic-link" href="#">Link with Icon <ion-icon name="open-outline"></ion-icon></a>
<a href="#">Link with Icon <ion-icon name="open-outline"></ion-icon></a>
</div>
</div>
<h3>Underline (.ionic-link-underline)</h3>
<h3>Underline (.ion-link-underline)</h3>
<div class="links" id="underline">
<div><a class="ionic-link-underline" href="#">Underline - Default</a></div>
<div><a class="ionic-link-underline ion-activated" href="#">Underline - Active</a></div>
<div><a class="ionic-link-underline ion-focused" href="#">Underline - Focused</a></div>
<div><a class="ionic-link-underline" href="">Underline - Visited</a></div>
<div><a class="ion-link-underline" href="#test-visited-link">Underline - Default</a></div>
<div><a class="ion-link-underline ion-activated" href="#">Underline - Active</a></div>
<div><a class="ion-link-underline ion-focused" href="#">Underline - Focused</a></div>
<div><a class="ion-link-underline" href="">Underline - Visited</a></div>
<div>
<a class="ionic-link-underline" href="#">Link with Icon <ion-icon name="open-outline"></ion-icon></a>
<a class="ion-link-underline" href="#">Link with Icon <ion-icon name="open-outline"></ion-icon></a>
</div>
</div>
<h3>Links in Content</h3>
<div class="links" id="links-in-content">
<div>
Lorem ipsum dolor sit amet consectetur, <a class="ionic-link" href="#">default link</a> adipisicing elit.
Lorem ipsum dolor sit amet consectetur, <a class="ion-link" href="#">default link</a> adipisicing elit.
</div>
<div>
Lorem ipsum dolor sit amet consectetur,
<a class="ionic-link-underline" href="#">underline link</a> adipisicing elit.
<a class="ion-link-underline" href="#">underline link</a> adipisicing elit.
</div>
</div>
<h3>Parent Element</h3>
<div class="links">
<div class="ionic-link" id="standalone-nested">
<div class="ion-link" id="standalone-nested">
<p>Lorem ipsum dolor sit amet consectetur, <a href="#">default link</a> adipisicing elit.</p>
</div>
<div class="ionic-link-underline" id="underline-nested">
<div class="ion-link-underline" id="underline-nested">
<p>Lorem ipsum dolor sit amet consectetur, <a href="#">underline link</a> adipisicing elit.</p>
</div>
</div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB