Detale robią różnicę. Naprawdę.
Klientka wchodzi na stronę i jeszcze zanim przeczyta pierwsze zdanie – już czuje czy ta strona jest dopracowana czy nie. Własny kursor to jeden z tych elementów które działają podprogowo – nikt nie myśli „o, jaki fajny kursor”, ale każdy czuje że strona jest wyjątkowa, spójna, przemyślana.
I nie, to nie jest rozwiązanie dla każdego projektu. Ale w odpowiednim kontekście – strona portfolio, agencja kreatywna, butikowy sklep z produktami premium, strona dla fotografa czy projektantki – własny kursor może być tym jednym detalem który sprawia że strona zapada w pamięć.
W tym artykule pokażę Ci jak to zrobić przez czysty CSS, przez JavaScript dla bardziej zaawansowanych efektów i jak to wdrożyć w WordPress. Bez wtyczek, bez ciężkich bibliotek, z pełną kontrolą nad efektem.
Czym tak naprawdę jest kursor w CSS?
Zanim przejdziemy do kodu, warto zrozumieć jak przeglądarka obsługuje kursor.
Przeglądarka domyślnie pokazuje kilka typów kursorów w zależności od kontekstu – strzałkę na zwykłych elementach, rączkę na linkach i przyciskach, krzyżyk tekstowy przy zaznaczaniu tekstu, kółko ładowania gdy coś się wczytuje. Wszystko to kontroluje właściwość CSS cursor.
I ta właściwość przyjmuje nie tylko słowa kluczowe jak pointer czy default – przyjmuje też własny plik graficzny przez funkcję url(). To właśnie ta możliwość otwiera drzwi do własnego kursora.
body {
cursor: url('kursor.png'), auto;
}
Drugi parametr po przecinku – auto – to fallback. Jeśli przeglądarka nie obsługuje pliku albo plik się nie załaduje, użyje domyślnego kursora systemowego. Ten fallback jest obowiązkowy – bez niego CSS jest nieprawidłowy.
Formaty plików i ograniczenia przeglądarek
Zanim zaczniesz tworzyć kursor, warto wiedzieć z czym pracujesz. Nie każdy format działa wszędzie i są konkretne limity wielkości.
Format .cur to natywny format kursora Windows. Obsługiwany przez wszystkie przeglądarki bez wyjątku. Możesz go stworzyć w dedykowanych edytorach jak IcoFX albo przez konwertery online.
Format PNG to najwygodniejsza opcja – tworzysz w Canvie, Figmie, Photoshopie, eksportujesz i gotowe. Obsługiwany przez Chrome, Edge i Firefox. Safari ma z nim problemy – dlatego zawsze podajesz fallback.
Format SVG – obsługiwany przez Chrome i Firefox, nie przez Safari. Lekki i skalowalny, ale najwęższe wsparcie przeglądarek.
Limity wielkości – to ważne. Przeglądarki mają różne limity maksymalnego rozmiaru niestandardowego kursora. Chrome i Firefox obsługują do 128x128px. Praktycznie jednak kursory powyżej 64x64px wyglądają już przesadnie. Optymalny rozmiar to 32x32px albo 64x64px.
Punkt aktywny (hotspot) – to miejsce na kursorze które „klika”. Dla standardowej strzałki to lewy górny róg (0,0). Możesz to zmienić w definicji kursora:
cursor: url('kursor.png') 16 16, auto;
Liczby 16 16 oznaczają że punkt aktywny jest w środku kursora 32x32px. Przy kursorze w kształcie koła – środek jako hotspot jest naturalny. Przy kursorze w kształcie strzałki – lewy górny róg (0 0).
Podstawowa implementacja – własna grafika jako kursor
Zacznijmy od najprostszego przypadku – podmieniasz domyślny kursor na własny plik graficzny.
/* Kursor dla całej strony */
body {
cursor: url('kursor.png'), auto;
}
/* Kursor rączki dla linków i przycisków */
a,
button,
[role="button"] {
cursor: url('kursor-klik.png'), pointer;
}
/* Kursor tekstowy przy zaznaczaniu */
p,
h1, h2, h3,
article {
cursor: url('kursor-tekst.png'), text;
}
Trzy selektory, trzy kursory – każdy dopasowany do kontekstu. Klientka przeglądająca stronę widzi spójny system kursorów który pasuje do estetyki marki.
Jak wgrać kursor do WordPress? Przez FTP do katalogu motywu potomnego – np. wp-content/themes/twoj-motyw-child/images/kursor.png. W CSS ścieżkę podajesz relatywnie do pliku CSS albo absolutnie:
cursor: url('/wp-content/themes/twoj-motyw-child/images/kursor.png'), auto;
Albo przez functions.php gdzie masz dostęp do funkcji WordPressa:
add_action('wp_head', 'wlasny_kursor_css');
function wlasny_kursor_css() {
$uri = get_stylesheet_directory_uri();
echo '<style>
body {
cursor: url("' . $uri . '/images/kursor.png"), auto;
}
a, button {
cursor: url("' . $uri . '/images/kursor-klik.png"), pointer;
}
</style>';
}
Obsługa wszystkich przeglądarek – właściwa kolejność
Żeby kursor działał wszędzie gdzie to możliwe, podajesz kilka formatów w kolejności od najbardziej preferowanego:
body {
cursor:
url('kursor.svg'), /* Chrome, Firefox */
url('kursor.png'), /* Chrome, Firefox, Edge */
url('kursor.cur'), /* wszystkie przeglądarki */
auto; /* ostateczny fallback */
}
Przeglądarka bierze pierwszy format który obsługuje. Safari skoczy od razu do .cur albo do auto. Chrome i Firefox użyją SVG.
Ukryj domyślny kursor i zrób własny przez JavaScript
CSS cursor: url() ma jedno duże ograniczenie – kursor jest grafiką i nie możesz go animować, dodać mu rozmytego śladu, sprawić żeby reagował na hover elementów inaczej niż przez podmianę pliku.
Jeśli chcesz naprawdę efektowny kursor – taki z animacją, ze świecącym kółkiem, z efektem magnetycznego przyciągania do przycisków – musisz zbudować go przez JavaScript.
Zasada jest prosta: ukrywasz systemowy kursor przez CSS i zastępujesz go własnym elementem HTML który podąża za myszą.
Krok 1 – ukryj systemowy kursor
* {
cursor: none !important;
}
!important jest potrzebne żeby nadpisać wszystkie inne reguły cursor – rączkę na linkach, strzałkę na elementach, kursor tekstowy.
Krok 2 – utwórz element kursora
.custom-cursor {
position: fixed;
top: 0;
left: 0;
width: 20px;
height: 20px;
background: #0444ac;
border-radius: 50%;
pointer-events: none; /* ważne - kursor nie może blokować kliknięć */
transform: translate(-50%, -50%);
transition: transform 0.1s ease;
z-index: 99999;
mix-blend-mode: difference; /* opcjonalnie - efekt inwersji kolorów */
}
Krok 3 – JavaScript który śledzi mysz
const cursor = document.createElement('div');
cursor.classList.add('custom-cursor');
document.body.appendChild(cursor);
document.addEventListener('mousemove', function(e) {
cursor.style.left = e.clientX + 'px';
cursor.style.top = e.clientY + 'px';
});
To podstawowy kursor który podąża za myszą. Prosto i działa.
Efekt opóźnienia – kursor który „ciągnie się” za myszą
Jeden z najpopularniejszych efektów kursorów na stronach portfolio. Zamiast natychmiastowego śledzenia myszy – kursor jakby płynął za nią z lekkim opóźnieniem. Sprawia wrażenie że ma masę, że jest fizyczny.
const cursor = document.querySelector('.custom-cursor');
let mouseX = 0, mouseY = 0;
let cursorX = 0, cursorY = 0;
const speed = 0.1; // im mniejsza wartość, tym większe opóźnienie
document.addEventListener('mousemove', function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
});
function animujKursor() {
// Interpolacja liniowa (lerp) - kursor "dogania" mysz
cursorX += (mouseX - cursorX) * speed;
cursorY += (mouseY - cursorY) * speed;
cursor.style.left = cursorX + 'px';
cursor.style.top = cursorY + 'px';
requestAnimationFrame(animujKursor);
}
animujKursor();
requestAnimationFrame sprawia że animacja jest płynna i zsynchronizowana z odświeżaniem ekranu – żadnych szarpnięć, żadnych problemów z wydajnością.
Wartość speed = 0.1 oznacza że kursor co klatkę przesuwa się o 10% odległości do myszy. Im mniejsza wartość tym większe opóźnienie – 0.05 daje bardzo leniwy kursor, 0.2 prawie natychmiastowy.
Kursor który reaguje na hover – efekt powiększenia przy linkach
Klasyczny i elegancki efekt – kursor zmienia rozmiar gdy najedziesz na link albo przycisk. Informuje użytkownika że element jest klikalny, bez potrzeby zmiany kursora na rączkę.
css
.custom-cursor {
position: fixed;
width: 12px;
height: 12px;
background: #0444ac;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
transition: width 0.3s ease,
height 0.3s ease,
background 0.3s ease;
z-index: 99999;
}
.custom-cursor.hover {
width: 40px;
height: 40px;
background: transparent;
border: 2px solid #0444ac;
}
javascript
const cursor = document.querySelector('.custom-cursor');
document.addEventListener('mousemove', function(e) {
cursor.style.left = e.clientX + 'px';
cursor.style.top = e.clientY + 'px';
});
// Dodaj klasę hover gdy mysz jest nad linkiem lub przyciskiem
const klikalneElementy = document.querySelectorAll('a, button, [role="button"], .klikalne');
klikalneElementy.forEach(el => {
el.addEventListener('mouseenter', () => cursor.classList.add('hover'));
el.addEventListener('mouseleave', () => cursor.classList.remove('hover'));
});
Efekt: mały wypełniony punkt na co dzień, duże puste kółko nad elementami klikalnymi. Przejście między stanami przez CSS transition jest płynne.
Kursor z efektem mix-blend-mode – inwersja kolorów
Ten efekt jest naprawdę efektowny i zaskakująco prosty do osiągnięcia.
.custom-cursor {
position: fixed;
width: 30px;
height: 30px;
background: white;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
z-index: 99999;
mix-blend-mode: difference;
}
mix-blend-mode: difference sprawia że kursor miesza się z tłem przez odjęcie kolorów. Biały kursor na ciemnym tle wygląda jak jasna plama. Biały kursor na jasnym tle wygląda jak ciemna plama. Na kolorowym tle – daje efekt inwersji kolorów.
To jeden z tych efektów które wyglądają dużo drożej niż są w implementacji.
Kursor z cząsteczkami – efekt śladu za kursorem
Bardziej zaawansowany efekt – za kursorem ciągnie się ślad małych cząsteczek które znikają.
function stworzCzasteczke(x, y) {
const czasteczka = document.createElement('div');
czasteczka.style.cssText = `
position: fixed;
width: 6px;
height: 6px;
background: #0444ac;
border-radius: 50%;
pointer-events: none;
left: ${x}px;
top: ${y}px;
transform: translate(-50%, -50%);
z-index: 99998;
transition: opacity 0.5s ease, transform 0.5s ease;
`;
document.body.appendChild(czasteczka);
// Animuj i usuń
setTimeout(() => {
czasteczka.style.opacity = '0';
czasteczka.style.transform = 'translate(-50%, -50%) scale(0)';
}, 50);
setTimeout(() => czasteczka.remove(), 600);
}
let ostatniaX = 0, ostatniaY = 0;
document.addEventListener('mousemove', function(e) {
// Twórz cząsteczkę tylko gdy kursor się poruszył o minimum 5px
// (bez tego przy powolnym ruchu jest ich za dużo)
const dx = e.clientX - ostatniaX;
const dy = e.clientY - ostatniaY;
if (Math.sqrt(dx*dx + dy*dy) > 5) {
stworzCzasteczke(e.clientX, e.clientY);
ostatniaX = e.clientX;
ostatniaY = e.clientY;
}
});
Jak wdrożyć w WordPress
Masz kilka opcji w zależności od tego co wolisz.
Opcja 1 – przez Insert Headers and Footers
CSS wklejasz w sekcję Header, JavaScript w sekcję Footer. Prosto i bez dotykania plików motywu.
Opcja 2 – przez functions.php w motywie potomnym
add_action('wp_enqueue_scripts', 'wlasny_kursor_skrypty');
function wlasny_kursor_skrypty() {
// Wgraj własny plik JS
wp_enqueue_script(
'wlasny-kursor',
get_stylesheet_directory_uri() . '/js/kursor.js',
[],
'1.0',
true // załaduj w footerze
);
// Wgraj własny plik CSS
wp_enqueue_style(
'wlasny-kursor-styl',
get_stylesheet_directory_uri() . '/css/kursor.css'
);
}
Tworzysz dwa pliki w motywie potomnym: /js/kursor.js z JavaScriptem i /css/kursor.css ze stylami kursora. Czyste, profesjonalne i zgodne z WordPress best practices.
Opcja 3 – inline przez wp_head
add_action('wp_head', 'wlasny_kursor_inline');
function wlasny_kursor_inline() { ?>
<style>
* { cursor: none !important; }
.custom-cursor {
position: fixed;
width: 20px;
height: 20px;
background: #0444ac;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
z-index: 99999;
}
</style>
<?php }
add_action('wp_footer', 'wlasny_kursor_js');
function wlasny_kursor_js() { ?>
<script>
const cursor = document.createElement('div');
cursor.classList.add('custom-cursor');
document.body.appendChild(cursor);
document.addEventListener('mousemove', e => {
cursor.style.left = e.clientX + 'px';
cursor.style.top = e.clientY + 'px';
});
</script>
<?php }
Ważne – własny kursor tylko na desktop
To jeden z najczęstszych błędów – zapominanie że na urządzeniach mobilnych i tabletach nie ma myszki. Własny kursor nie ma sensu na touch devices, a cursor: none może powodować problemy.
Zawsze ograniczaj własny kursor do urządzeń z myszką:
/* Własny kursor TYLKO na urządzeniach nie-dotykowych */
@media (pointer: fine) {
* {
cursor: none !important;
}
.custom-cursor {
display: block;
}
}
/* Na urządzeniach dotykowych - ukryj element kursora */
@media (pointer: coarse) {
.custom-cursor {
display: none;
}
}
Media query pointer: fine wykrywa urządzenia ze wskaźnikiem o dużej precyzji – czyli myszkę. pointer: coarse to ekrany dotykowe.
W JavaScript dodaj analogiczne sprawdzenie:
// Uruchom własny kursor tylko jeśli jest mysz
if (window.matchMedia('(pointer: fine)').matches) {
// cały kod kursora tutaj
}
Typowe błędy przy własnym kursorze
Brak pointer-events: none – jeśli zapomnisz dodać tę właściwość do elementu kursora, będzie on blokował kliknięcia. Klientka klika link – klika kursor zamiast linka. Zawsze dodawaj pointer-events: none do elementu kursora.
Za duży kursor – kursor 100x100px to za dużo. Zakrywa treść, jest irytujący. Trzymaj się 20-40px dla eleganckiego efektu.
Brak fallbacka w CSS cursor: url() – bez fallbacka auto na końcu CSS jest nieprawidłowy i przeglądarka może zignorować całą regułę.
Własny kursor na mobile – jak już pisałam wyżej. Zawsze sprawdzaj pointer: fine.
Za bardzo skomplikowany efekt śladu – tworzenie setek elementów DOM co kilka milisekund zabija wydajność strony. Jeśli robisz ślad cząsteczek – ogranicz częstotliwość tworzenia nowych elementów i zawsze usuwaj stare przez remove().
Kursor znika za modalnymi i popupami – jeśli popup ma z-index: 9999, a kursor ma z-index: 9998, kursor chowa się pod popupem. Daj kursorowi z-index: 999999 albo dynamicznie zarządzaj z-indexem.
Kiedy własny kursor to dobry pomysł – a kiedy nie
Własny kursor ma sens gdy jest częścią spójnej koncepcji wizualnej strony – nie jako ozdobnik dla ozdobnika.
Dobrze sprawdza się przy stronach portfolio fotografów i ilustratorów, stronach agencji kreatywnych, butikowych sklepach z produktami luksusowymi, landing page’ach dla konkretnych kampanii, stronach eventowych i kulturalnych.
Nie sprawdza się przy blogach edukacyjnych i informacyjnych – odciąga uwagę od treści. Przy sklepach WooCommerce z dużym asortymentem – kursor powinien być maksymalnie transparentny. Przy stronach korporacyjnych gdzie liczy się zaufanie i profesjonalizm w tradycyjnym sensie.
Zasada jest prosta: jeśli pierwszą myślą po wdrożeniu jest „ale fajne”, a drugą „ale czy to nie przeszkadza” – prawdopodobnie przeszkadza. Własny kursor powinien być odczuwalny podprogowo, nie pierwszoplanowy.
Kilka słów na zakończenie
Własny kursor to jedno z tych rozwiązań które kosztuje kilkanaście linijek kodu, a może naprawdę wyróżnić stronę wizualnie.
Zacznij od prostego cursor: url() jeśli potrzebujesz tylko własnej grafiki. Jeśli chcesz efektu z opóźnieniem albo hover – JavaScript z requestAnimationFrame. Jeśli chcesz czegoś naprawdę efektownego – mix-blend-mode: difference za darmo daje wow efekt.
Pamiętaj o mobile, pamiętaj o fallbackach, pamiętaj o pointer-events: none.
I zawsze pytaj: czy ten kursor służy stronie, czy strona służy kursorowi?
Dołącz do Przystani Specek – miejsca, gdzie kobiety uczą się budować własne strony, sklepy, platformy kursowe i marki online - bez stresu, w zgodzie z sobą, ze wsparciem mentorki i cudownej społeczności innych Specek.👉 Kliknij i wejdź na pokład