CSS: menebalkan beberapa teks tanpa mengubah ukuran wadahnya

119

Saya memiliki menu navigasi horizontal, yang pada dasarnya hanya a <ul>dengan elemen yang diatur berdampingan. Saya tidak mendefinisikan lebar, tetapi hanya menggunakan padding, karena saya ingin lebar ditentukan oleh lebar item menu. Saya menebalkan item yang saat ini dipilih.

Masalahnya adalah dalam huruf tebal, kata tersebut menjadi sedikit lebih lebar, yang menyebabkan elemen lainnya bergeser sedikit ke kiri atau kanan. Adakah cara cerdas untuk mencegah hal ini terjadi? Sesuatu di sepanjang garis memberitahu padding untuk mengabaikan lebar ekstra yang disebabkan oleh bolding? Pikiran pertama saya adalah mengurangi beberapa piksel dari padding elemen "aktif", tetapi jumlahnya bervariasi.

Jika memungkinkan, saya ingin menghindari pengaturan lebar statis pada setiap entri dan kemudian memusatkan sebagai lawan dari solusi padding yang saya miliki saat ini, untuk membuat perubahan di masa mendatang menjadi sederhana.

Mala
sumber
mengapa ukuran berubah menjadi masalah? Apakah itu entah bagaimana mengacaukan tata letak?
Chaulky
Saya pikir pertanyaan pemrograman web paling baik ditanyakan di Stack Overflow. Mungkin mod akan memindahkan ini ke sana.
Ciaran
2
Chaulky: karena ada beberapa hal yang lebih saya benci, dari segi tata letak, daripada saat tombol yang seharusnya Anda coba klik melompat-lompat
Mala
doejo.com/blog/… adalah salah satu solusi yang saya temukan sesuai dengan apa yang dibicarakan John dan Blowski tentang jscript.
Sulfrog

Jawaban:

152

Saya memiliki masalah yang sama, tetapi mendapatkan efek yang sama dengan sedikit kompromi, saya menggunakan text-shadow sebagai gantinya.

li:hover {text-shadow:0px 0px 1px black;}

Inilah contoh yang berfungsi:

body {
  font-family: segoe ui;
}

ul li {
  display: inline-block;
  border-left: 1px solid silver;
  padding: 5px
}

.textshadow :hover {
  text-shadow: 0px 0px 1px black;
}

.textshadow-alt :hover {
  text-shadow: 1px 0px 0px black;
}

.bold :hover {
  font-weight: bold;
}
<ul class="textshadow">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li><code>text-shadow: 0px 0px 1px black;</code></li>
</ul>

<ul class="textshadow-alt">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li><code>text-shadow: 1px 0px 0px black;</code></li>
</ul>

<ul class="bold">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li><code>font-weight: bold;</code></li>
</ul>

contoh jsfiddle

Thorgeir
sumber
51
Saya suka solusi ini, meskipun saya sarankan untuk membalik yang itu menjadi 1px 0px 0px. Terlihat sedikit lebih berani.
M. Herold
Saya membutuhkan solusi khusus css dan inilah jawabannya.
JCasso
Anda benar-benar jenius! kesederhanaan membuatnya luar biasa!
lufi
1
Hanya menambahkan hasil li:hover {text-shadow: 1px 0 0 black;}teks dengan jarak yang terlalu sedikit di antara huruf. Untuk meningkatkannya lagi, kami juga menetapkanli {letter-spacing: 1px;}
Patrick Hammer
5
Saya menggunakan -0.5px 0 #fff, 0.5px 0 #fff, karena kita bisa melihat celah kecil antara teks itu sendiri dan bayangannya. Dan juga saat teks dicetak tebal, itu menambah bobot di kedua sisi.
atorscho
101

Solusi kerja terbaik menggunakan :: after

HTML

<li title="EXAMPLE TEXT">
  EXAMPLE TEXT
</li>

CSS

li::after {
  display: block;
  content: attr(title);
  font-weight: bold;
  height: 1px;
  color: transparent;
  overflow: hidden;
  visibility: hidden;
}

Ia menambahkan elemen semu yang tidak terlihat dengan lebar teks tebal, bersumber dari titleatribut.

The text-shadowsolusi terlihat tidak alami pada Mac dan tidak memanfaatkan semua keindahan yang teks rendering pada Mac penawaran .. :)

http://jsfiddle.net/85LbG/

Kredit: https://stackoverflow.com/a/20249560/5061744

workaholic_gangster911
sumber
11
Ini adalah solusi paling andal dan bersih , ini hanya menyediakan ruang untuk teks tebal di elemen. Dalam kasus saya, pseudo-element tambahan menyebabkan perubahan ketinggian. Menambahkan negatif margin-topke ::afterblok menyelesaikannya.
Vaclav Novotny
2
Solusi ini bagus! Saya menggunakan JS untuk menambahkan atribut "data-content" yang berisi teks elemen sehingga saya dapat menghindari perubahan HTML.
mistykristie
1
Mengagumkan. Ini harus menjadi jawaban terbaik. Perhatikan bahwa jika elemen berbeda dari li Anda mungkin harus menggunakan display: block; di: setelah elemen induk.
Blackbam
Solusi bagus! Bekerja dengan baik dengan :: before juga, dalam kasus saya ini mencegah margin tambahan di bagian bawah.
Thomas Champion
Terima kasih atas solusi ini. Saya awalnya menggunakan text-shadow tetapi ini tidak berfungsi di Safari karena membulatkan nilai desimal. Karena saya menggunakan 0.1px, ini dibulatkan menjadi 0. Solusi Anda bekerja dengan sempurna. Saya hanya mengganti atribut judul dengan nama karena saya tidak ingin tooltips muncul
Jonathan Cardoz
32

Solusi yang paling portabel dan menyenangkan secara visual adalah dengan menggunakan text-shadow. Ini merevisi dan menunjukkan contoh jawaban Thorgeir menggunakan Alexxali dan tweak saya sendiri:

  li:hover { text-shadow: -0.06ex 0 black, 0.06ex 0 black; }

Ini menempatkan "bayangan" kecil dalam warna hitam (gunakan nama / kode warna font Anda sebagai ganti blackjika perlu) di kedua sisi setiap huruf menggunakan unit yang akan diskalakan dengan benar dengan rendering font.

peringatan Peringatan: px nilai mendukung nilai desimal, tetapi tidak akan terlihat bagus saat ukuran font berubah (misalnya pengguna menskalakan tampilan dengan Ctrl+ +). Gunakan nilai relatif sebagai gantinya.

Jawaban ini menggunakan pecahan exunit karena diskalakan dengan font.
Di ~ kebanyakan default browser * , mengharapkan 1ex8pxdan karenanya 0.025ex0.1px.

Lihat diri mu sendiri:

li             { color: #000; } /* set text color just in case */
.shadow0       { text-shadow: inherit; }
.shadow2       { text-shadow: -0.02ex 0 #000, 0.02ex 0 #000; }
.shadow4       { text-shadow: -0.04ex 0 #000, 0.04ex 0 #000; }
.shadow6       { text-shadow: -0.06ex 0 #000, 0.06ex 0 #000; }
.shadow8       { text-shadow: -0.08ex 0 #000, 0.08ex 0 #000; }
.bold          { font-weight: bold; }
.bolder        { font-weight: bolder; }
.after span        { display:inline-block; font-weight: bold; } /* workaholic… */
.after:hover span  { font-weight:normal; }
.after span::after { content: attr(title); font-weight: bold; display:block; 
                     height: 0; overflow: hidden; }
.ltrsp         { letter-spacing:0; font-weight:bold; } /* @cgTag */
li.ltrsp:hover { letter-spacing:0.0125ex; }
li:hover       { font-weight: normal!important; text-shadow: none!important; }
<li class="shadow0">MmmIii123 This line tests shadow0 (plain)</li>
<li class="shadow2">MmmIii123 This line tests shadow2 (0.02ex)</li>
<li class="shadow4">MmmIii123 This line tests shadow4 (0.04ex)</li>
<li class="shadow6">MmmIii123 This line tests shadow6 (0.06ex)</li>
<li class="shadow8">MmmIii123 This line tests shadow8 (0.08ex)</li>
<li class="after"><span title="MmmIii123 This line tests [title]"
                   >MmmIii123 This line tests [title]</span> (@workaholic…)</li>
<li class="ltrsp"  >MmmIii123 This line tests ltrsp (@cgTag)</li>
<li class="bold"   >MmmIii123 This line tests bold</li>
<li class="bolder" >MmmIii123 This line tests bolder</li>
<li class="shadow2 bold">MmmIii123 This line tests shadow2 (0.02ex) + bold</li>
<li class="shadow4 bold">MmmIii123 This line tests shadow4 (0.04ex) + bold</li>
<li class="shadow6 bold">MmmIii123 This line tests shadow6 (0.06ex) + bold</li>
<li class="shadow8 bold">MmmIii123 This line tests shadow8 (0.08ex) + bold</li>

Arahkan kursor ke atas garis yang dirender untuk melihat perbedaannya dari teks standar.

Ubah tingkat zoom browser Anda ( Ctrl+ +dan Ctrl+ -) untuk melihat perbedaannya.

Saya menambahkan dua solusi lain di sini untuk perbandingan: Trik penspasian huruf @ cgTag , yang tidak berfungsi dengan baik karena melibatkan menebak rentang lebar font, dan @ workaholic_gangster911's :: setelah trik menggambar , yang menyisakan ruang ekstra yang canggung sehingga teks tebal dapat meluas tanpa menyentuh item teks yang berdekatan (saya meletakkan atribusi setelah teks tebal sehingga Anda dapat melihat bagaimana itu tidak bergerak).


Di masa mendatang, kami akan memiliki lebih banyak font variabel yang mampu melakukan hal-hal seperti mengubah kelas font melalui font-variation-settings. Dukungan browser sedang ditingkatkan (Chrome 63+, Firefox 62+) tetapi ini masih membutuhkan lebih dari sekedar font standar dan beberapa font yang ada mendukungnya.

Jika Anda menyematkan font variabel, Anda akan dapat menggunakan CSS seperti ini:

/* Grade: Increase the typeface's relative weight/density */
@supports (font-variation-settings: 'GRAD' 150) {
  li:hover { font-variation-settings: 'GRAD' 150; }
}
/* Failover for older browsers: tiny shadows at right & left of the text
 * (replace both instances of "black" with the font color) */
@supports not (font-variation-settings: 'GRAD' 150) {
  li:hover { text-shadow: -0.06ex 0 black, 0.06ex 0 black; }
}

Ada demo langsung dengan penggeser untuk dimainkan dengan berbagai tingkatan di Panduan Font Variabel Mozilla. Google Pengenalan font variabel di web memiliki GIF animasi menunjukkan toggle antara kelas tinggi dan tidak ada kelas:

animasi demo font Amstelvar Alpha dengan sumbu toggling grade

Adam Katz
sumber
1
Sangat sederhana, sangat indah.
Randy Hall
18

Saya menemukan bahwa sebagian besar font memiliki ukuran yang sama saat Anda menyesuaikan spasi huruf sebesar 1px.

a {
   letter-spacing: 1px;
}

a:hover {
   font-weight: bold;
   letter-spacing: 0px;
}

Sementara ini memang mengubah font biasa sehingga setiap huruf memiliki spasi piksel ekstra. Untuk menu, judulnya sangat pendek sehingga tidak ada masalah.

Reactgular
sumber
3
ini adalah solusi terbaik dan paling diremehkan, meskipun saya mengubahnya sehingga dimulai dengan 0 dan beralih ke spasi huruf negatif saat dicetak tebal. Anda juga harus menyesuaikannya untuk setiap font dan ukuran font. Saya juga memperbarui biola @ Thorgeir untuk memasukkan ini (sebagai solusi kedua) jsfiddle.net/dJcPn/50/
robotik
Browser modern sekarang mendukung akurasi sub-piksel. Jadi, Anda dapat menyesuaikan jarak menggunakan 0.98pxatau pecahan yang lebih kecil.
Reactgular
Ini terlihat agak aneh karena algoritma spasi tidak persis sama (beberapa huruf menari-nari sedikit) dan, yang lebih penting, ini tidak berfungsi ketika font diskalakan, bahkan jika Anda mengonversi 1pxke nilai relatif seperti 0.025exatau 0.0125ex. Lihat jawaban saya untuk demonstrasi langsung.
Adam Katz
@AdamKatz Saya curiga rendering font telah berubah sejak jawaban ini diposting, dan itu sangat tergantung pada font apa yang Anda gunakan.
Reactgular
5

Untuk jawaban yang lebih mutakhir, Anda dapat menggunakan -webkit-text-stroke-width:

.element {
  font-weight: normal;
}

.element:hover {
  -webkit-text-stroke-width: 1px;
  -webkit-text-stroke-color: black;
}

Hal ini untuk menghindari elemen semu (yang merupakan nilai tambah bagi pembaca layar) dan bayangan teks (yang terlihat berantakan dan masih dapat membuat sedikit efek 'lompatan') atau menyetel lebar tetap (yang mungkin tidak praktis).

Ini juga memungkinkan Anda untuk mengatur elemen menjadi lebih tebal dari 1px (secara teoritis, Anda dapat membuat font setebal yang Anda suka dan juga bisa menjadi latihan yang jelek untuk membuat versi tebal dari font yang tidak memiliki tebal varian, seperti font khusus ( edit: font variabel mengurangi saran ini ). Meskipun hal ini harus dihindari karena mungkin akan membuat beberapa font tampak kasar dan tidak rata)

Saya ini pasti berfungsi di Edge, Firefox, Chrome dan Opera (pada saat posting) dan di Safari ( edit: @Lars Blumberg terima kasih telah mengonfirmasi itu ). Ini TIDAK berfungsi di IE11 atau di bawahnya.

Perhatikan juga, ini menggunakan -webkitawalan, jadi ini bukan standar dan dukungan dapat dibatalkan di masa mendatang, jadi jangan mengandalkan ini tebal sangat penting - sebaiknya hindari teknik ini kecuali hanya estetika.

Oliver
sumber
1
Juga berfungsi di Safari 13.0.5. Solusi terbersih untuk saya sejauh ini.
Lars Blumberg
4

Sayangnya, satu-satunya cara untuk menghindari perubahan lebar saat teks dicetak tebal adalah dengan menentukan lebar item daftar, namun seperti yang Anda nyatakan melakukan ini secara manual memakan waktu dan tidak dapat diskalakan.

Satu-satunya hal yang dapat saya pikirkan adalah menggunakan beberapa javascript yang menghitung lebar tab sebelum ditebalkan, dan kemudian menerapkan lebar pada saat yang sama harus menebalkan (baik saat Anda mengarahkan atau mengklik).

ajcw
sumber
hm, saya akan bereksperimen dengan ini, meskipun saya ingin setidaknya terlihat masuk akal (mis. dicetak tebal) untuk pengguna non JS. Mungkin saya bisa mengirimnya tebal, menggunakan JSuntuk melepasnya, menghitung lebarnya, lalu menebalkannya lagi? Atau itu konyol?
Mala
Ya, sepertinya itu cara terbaik untuk mengakomodasi pengguna non-javascript.
ajcw
2

Gunakan JavaScript untuk menyetel lebar tetap li berdasarkan konten yang tidak dicetak tebal, lalu cetak tebal konten dengan menerapkan gaya ke <a>tag (atau tambahkan rentang jika <li>tidak memiliki turunan ).

Dan Blows
sumber
Ups - maaf telah mengulangi: $
Dan Blows
Terima kasih atas jawaban Anda :)
Mala
@ Mala Apakah Anda menemukan solusi? Lucunya, saya punya masalah serupa.
Dan Blows
1

Ini adalah pertanyaan yang sangat lama, tetapi saya mengunjunginya kembali karena saya memiliki masalah ini dalam aplikasi yang saya kembangkan dan menemukan semua jawaban yang diinginkan di sini.

(Lewati paragraf ini untuk TL; DR ...)Saya menggunakan font web Gotham dari cloud.typography.com, dan saya memiliki tombol yang mulai kosong (dengan tepi / teks putih dan latar belakang transparan) dan memperoleh warna latar belakang saat melayang. Saya menemukan bahwa beberapa warna latar belakang yang saya gunakan tidak kontras dengan teks putih, jadi saya ingin mengubah teks menjadi hitam untuk tombol-tombol itu, tetapi - entah karena trik visual atau metode anti-aliasing yang umum - gelap teks pada latar belakang terang selalu tampak lebih ringan daripada teks putih pada latar belakang gelap. Saya menemukan bahwa meningkatkan bobot dari 400 menjadi 500 untuk teks gelap mempertahankan bobot "visual" yang hampir persis sama. Namun, itu meningkatkan lebar tombol dengan jumlah kecil - sebagian kecil dari piksel - tapi itu cukup untuk membuat tombol tampak "bergetar" sedikit, yang ingin saya singkirkan.

Larutan:

Jelas sekali, ini adalah masalah yang sangat rewel sehingga diperlukan solusi yang rumit. Pada akhirnya saya menggunakan negatif letter-spacingpada teks yang lebih tebal seperti yang direkomendasikan cgTag di atas, tetapi 1px akan terlalu berlebihan, jadi saya hanya menghitung dengan tepat lebar yang saya perlukan.

Dengan memeriksa tombol di devtools Chrome, saya menemukan bahwa lebar default tombol saya adalah 165.47px, dan 165.69px saat hover, selisih 0.22px. Tombol tersebut memiliki 9 karakter, jadi:

0,22 / 9 = 0,024444 piksel

Dengan mengonversinya ke unit em saya bisa membuat penyesuaian ukuran font agnostik. Tombol saya menggunakan ukuran font 16px, jadi:

0,024444 / 16 = 0,001527em

Jadi untuk font khusus saya, CSS berikut menjaga tombol dengan lebar yang sama persis saat hover:

.btn {
  font-weight: 400;
}

.btn:hover {
  font-weight: 500;
  letter-spacing: -0.001527em;
}

Dengan sedikit pengujian dan menggunakan rumus di atas, Anda dapat menemukan nilai yang tepat letter-spacinguntuk situasi Anda, dan itu akan berfungsi terlepas dari ukuran fontnya.

Satu-satunya peringatan adalah bahwa browser yang berbeda menggunakan penghitungan sub-piksel yang sedikit berbeda, jadi jika Anda membidik tingkat presisi sub-piksel-sempurna OCD ini, Anda harus mengulangi pengujian dan menetapkan nilai yang berbeda untuk setiap browser. Gaya CSS bertarget browser umumnya tidak disukai , untuk alasan yang bagus, tetapi saya pikir ini adalah salah satu kasus penggunaan di mana itu satu-satunya pilihan yang masuk akal.

dannymcgee
sumber
0

Pertanyaan menarik. Saya kira Anda menggunakan float, bukan?

Yah, saya tidak tahu teknik apa pun yang dapat Anda gunakan untuk menghilangkan pembesaran font ini, maka mereka akan mencoba menyesuaikan dengan lebar minimum yang diperlukan - dan ketebalan font yang bervariasi akan mengubah nilai ini.

Solusi unik yang saya tahu untuk menghindari perubahan ini adalah solusi yang Anda katakan tidak Anda inginkan: mengatur ukuran tetap ke li.

Davis Peixoto
sumber
0

Anda dapat menerapkan ini seperti menu hover "Belanja berdasarkan departemen" di amazon.com. Ini menggunakan div lebar. Anda dapat membuat div lebar dan menyembunyikan bagian kanannya

Andrus
sumber
0

UPDATE: Harus menggunakan tag B untuk judul karena di IE11 pseudo class i: after tidak muncul ketika saya memiliki visibility: hidden.

Dalam kasus saya, saya ingin menyelaraskan kotak centang / radio input (yang dirancang khusus) dengan teks label di mana teks menjadi tebal ketika input dicentang.

Solusi yang disediakan di sini tidak berfungsi untuk saya di Chrome. Penjajaran vertikal input dan label menjadi kacau dengan: after psuedo class dan -margins tidak memperbaiki ini.

Berikut adalah perbaikan di mana Anda tidak mendapatkan masalah dengan perataan vertikal.

/* checkbox and radiobutton */
label
{
    position: relative;
    display: inline-block;
    padding-left: 30px;
    line-height: 28px;
}

/* reserve space of bold text so that the container-size remains the same when the label text is set to bold when checked. */
label > input + b + i
{
    font-weight: bold;
    font-style: normal;
    visibility: hidden;
}

label > input:checked + b + i
{
    visibility: visible;
}

/* set title attribute of label > b */
label > input + b:after
{
    display: block;
    content: attr(title);
    font-weight: normal;
    position: absolute;
    left: 30px;
    top: -2px;
    visibility: visible;
}

label > input:checked + b:after
{
    display: none;
}

label > input[type="radio"],
label > input[type="checkbox"]
{
    position: absolute;
    visibility: hidden;
    left: 0px;
    margin: 0px;
    top: 50%;
    transform: translateY(-50%);
}

    label > input[type="radio"] + b,
    label > input[type="checkbox"]  + b
    {
        display: block;
        position: absolute;
        left: 0px;
        margin: 0px;
        top: 50%;
        transform: translateY(-50%);
        width: 24px;
        height: 24px;
        background-color: #00a1a6;
        border-radius: 3px;
    }

    label > input[type="radio"] + b
    {
        border-radius: 50%;
    }

    label > input:checked + b:before
    {
        display: inline-block;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%) rotate(45deg);
        content: '';
        border-width: 0px 3px 3px 0px;
        border-style: solid;
        border-color: #fff;
        width: 4px;
        height: 8px;
        border-radius: 0px;
    }

    label > input[type="checkbox"]:checked + b:before
    {
        transform: translate(-50%, -60%) rotate(45deg);
    }

    label > input[type="radio"]:checked + b:before
    {
        border-width: 0px;
        border-radius: 50%;
        width: 8px;
        height: 8px;
    }
<label><input checked="checked" type="checkbox"/><b title="Male"></b><i>Male</i></label>
<label><input type="checkbox"/><b title="Female"></b><i>Female</i></label>

Erik
sumber