Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"/> | |
| <meta content="width=device-width, initial-scale=1.0" name="viewport"/> | |
| <title>Title hover animation β black β colors β blue</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;600;700&display=swap" rel="stylesheet"/> | |
| <style> | |
| :root { | |
| --infinite: #032D42; /* rest / black */ | |
| --indigo: #7661FF; | |
| --blue: #52B8FF; /* FINAL settle color */ | |
| --green: #63DF4E; | |
| } | |
| body { | |
| font-family: 'Hanken Grotesk', system-ui, sans-serif; | |
| background: #faf9fb; | |
| color: var(--infinite); | |
| margin: 0; | |
| padding: 64px 48px; | |
| } | |
| h1 { font-size: 20px; font-weight: 700; margin: 0 0 4px; } | |
| .sub { color: #5b6b75; font-size: 14px; margin: 0 0 40px; } | |
| .note { color: #5b6b75; font-size: 13px; max-width: 720px; line-height: 1.5; } | |
| .note b { color: var(--infinite); } | |
| .row { | |
| display: grid; | |
| grid-template-columns: 200px 1fr; | |
| align-items: center; | |
| gap: 32px; | |
| padding: 30px 0; | |
| border-top: 1px solid #E1E8ED; | |
| } | |
| .meta b { font-size: 15px; display: block; } | |
| .meta span { font-size: 12px; color: #5b6b75; } | |
| .title { | |
| font-size: 30px; | |
| font-weight: 700; | |
| letter-spacing: -0.02em; | |
| text-decoration: none; | |
| cursor: pointer; | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| } | |
| .title:focus-visible { | |
| outline: 2px solid var(--indigo); | |
| outline-offset: 4px; | |
| border-radius: 4px; | |
| } | |
| /* ========================================================= | |
| Take A β SWEEP TO BLUE | |
| One gradient. Window slides LβR: infinite plateau β rainbow | |
| β blue plateau. Reverses smoothly on un-hover. | |
| ========================================================= */ | |
| .sweep { | |
| background-image: linear-gradient(90deg, | |
| var(--infinite) 0%, var(--infinite) 30%, | |
| var(--indigo) 42%, var(--green) 52%, var(--blue) 64%, | |
| var(--blue) 70%, var(--blue) 100%); | |
| background-size: 320% 100%; | |
| background-position: 0% 0; /* rest window = infinite plateau */ | |
| color: transparent; | |
| -webkit-text-fill-color: transparent; | |
| transition: background-position 0.5s ease; /* smooth revert */ | |
| } | |
| .sweep:hover, .sweep:focus-visible { | |
| animation: sweep-to-blue 0.9s ease forwards; | |
| } | |
| @keyframes sweep-to-blue { | |
| 0% { background-position: 0% 0; } | |
| 100% { background-position: 100% 0; } /* window = blue plateau */ | |
| } | |
| /* ========================================================= | |
| Take B β BLOOM, THEN SETTLE TO BLUE | |
| Colors bloom from center, then fade to solid blue. | |
| ========================================================= */ | |
| .bloom { | |
| background-image: radial-gradient(circle at 50% 50%, | |
| var(--infinite) 0%, var(--infinite) 10%, | |
| var(--indigo) 34%, var(--green) 58%, var(--blue) 80%, var(--blue) 100%); | |
| background-position: center; | |
| background-repeat: no-repeat; | |
| background-size: 600% 600%; | |
| color: transparent; | |
| -webkit-text-fill-color: var(--infinite); /* rest = solid infinite */ | |
| transition: -webkit-text-fill-color 0.4s ease, background-size 0.4s ease; /* smooth revert */ | |
| } | |
| .bloom:hover, .bloom:focus-visible { | |
| animation: bloom-settle 1s ease forwards; | |
| } | |
| @keyframes bloom-settle { | |
| 0% { background-size: 600% 600%; -webkit-text-fill-color: var(--infinite); } | |
| 20% { -webkit-text-fill-color: transparent; } | |
| 55% { background-size: 130% 130%; -webkit-text-fill-color: transparent; } | |
| 100% { background-size: 130% 130%; -webkit-text-fill-color: var(--blue); } /* fade to blue */ | |
| } | |
| /* accessibility: no motion β jump straight to the final blue, no journey */ | |
| @media (prefers-reduced-motion: reduce) { | |
| .sweep, .bloom { transition: -webkit-text-fill-color 0.001s; } | |
| .sweep:hover, .sweep:focus-visible, | |
| .bloom:hover, .bloom:focus-visible { | |
| animation: none; | |
| color: var(--blue); | |
| -webkit-text-fill-color: var(--blue); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>Title hover β black β color animation β settles to blue</h1> | |
| <p class="sub">Hover (or Tab to) each title. Rest = infinite-blue. End-of-animation = bright-blue, held while hovered.</p> | |
| <div class="row"> | |
| <div class="meta"><b>A Β· Sweep β blue</b><span>infinite β rainbow sweep β settles blue Β· 0.9s</span></div> | |
| <a class="title sweep" href="#" tabindex="0">EnterpriseOps-Gym</a> | |
| </div> | |
| <div class="row"> | |
| <div class="meta"><b>B Β· Bloom β blue</b><span>colors bloom from center β fade to blue Β· 1.0s</span></div> | |
| <a class="title bloom" href="#" tabindex="0">EnterpriseOps-Gym</a> | |
| </div> | |
| <div class="row"> | |
| <div class="meta"><b>A Β· Sweep β blue</b><span>second title</span></div> | |
| <a class="title sweep" href="#" tabindex="0">EVA-Bench</a> | |
| </div> | |
| <div class="row"> | |
| <div class="meta"><b>B Β· Bloom β blue</b><span>second title</span></div> | |
| <a class="title bloom" href="#" tabindex="0">EVA-Bench</a> | |
| </div> | |
| <div class="row" style="border-bottom: 1px solid #E1E8ED;"> | |
| <div class="meta"><b>Note</b></div> | |
| <p class="note"><b>Contrast flag:</b> final blue <code>#52B8FF</code> on white is low-contrast (~2:1, below WCAG AA for text). Fine as a transient hover state, but if titles should pass AA while hovered, settle on a deeper blue like <code>#006DAA</code> instead. Say which.</p> | |
| </div> | |
| </body> | |
| </html> | |