CSS: tô đậm một số văn bản mà không thay đổi kích thước vùng chứa của nó


119

Tôi có một menu điều hướng ngang, về cơ bản chỉ là một menu <ul>với các phần tử được đặt cạnh nhau. Tôi không xác định chiều rộng, mà chỉ đơn giản sử dụng padding, vì tôi muốn chiều rộng được xác định bằng chiều rộng của mục menu. Tôi in đậm mục hiện đang chọn.

Vấn đề là khi in đậm, từ này trở nên rộng hơn một chút, điều này làm cho các phần tử còn lại hơi dịch sang trái hoặc phải. Có cách nào thông minh để ngăn điều này xảy ra không? Một cái gì đó dọc theo dòng nói cho padding bỏ qua chiều rộng tăng thêm do bolding? Suy nghĩ đầu tiên của tôi là chỉ cần trừ một vài pixel khỏi phần đệm của phần tử "hoạt động", nhưng số lượng này thay đổi.

Nếu có thể, tôi muốn tránh đặt chiều rộng tĩnh trên mỗi mục nhập và sau đó căn giữa trái ngược với giải pháp đệm tôi hiện có, để thực hiện các thay đổi trong tương lai đối với các mục nhập đơn giản.


tại sao thay đổi kích thước là một vấn đề? Nó có làm rối bố cục bằng cách nào đó không?
Chaulky

Tôi nghĩ câu hỏi lập trình web tốt nhất nên được hỏi trên Stack Overflow. Có thể một mod sẽ di chuyển cái này ở đó.
Ciaran

2
Chaulky: vì có vài điều tôi ghét hơn, bố trí-khôn ngoan, so với khi nút bạn đang phải cố gắng nhấp nhảy xung quanh
Mala

doejo.com/blog/… là một giải pháp mà tôi đã tìm thấy nó thực hiện chính xác những gì John và Blowski đã nói về jscript.
thebulfrog

Câu trả lời:


152

Tôi đã gặp vấn đề tương tự, nhưng có hiệu ứng tương tự với một chút thỏa hiệp, thay vào đó tôi đã sử dụng text-shadow.

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

Đây là một ví dụ hoạt động:

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>

ví dụ jsfiddle


51
Tôi thích giải pháp này, mặc dù tôi khuyên bạn nên chuyển giải pháp đó thành 1px 0px 0px. Trông giống như đậm hơn một chút.
M. Herold

Tôi cần một giải pháp chỉ css và đây là câu trả lời.
JCasso

bạn là một thiên tài thực sự! sự đơn giản làm cho nó tuyệt vời!
lufi

1
Chỉ thêm vào li:hover {text-shadow: 1px 0 0 black;}dẫn đến văn bản có quá ít khoảng cách giữa các chữ cái. Để cải thiện điều đó một lần nữa, chúng tôi cũng đặtli {letter-spacing: 1px;}
Patrick Hammer

5
Tôi đã sử dụng -0.5px 0 #fff, 0.5px 0 #fff, bởi vì chúng ta có thể thấy khoảng cách nhỏ giữa văn bản và bóng. Và cũng như khi văn bản được in đậm, nó sẽ tăng thêm trọng lượng cho cả hai bên.
atorscho

101

Giải pháp làm việc tốt nhất bằng cách sử dụng :: sau

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;
}

Nó thêm một phần tử giả vô hình với chiều rộng của văn bản in đậm, lấy nguồn theo titlethuộc tính.

Các text-shadow giải pháp trông không tự nhiên trên máy Mac và không sử dụng tất cả các vẻ đẹp mà văn bản render trên Mac Mời .. :)

http://jsfiddle.net/85LbG/

Tín dụng: https://stackoverflow.com/a/20249560/5061744


11
Đây là giải pháp sạch sẽ và đáng tin cậy nhất , nó chỉ dành không gian cho văn bản in đậm trong phần tử. Trong trường hợp của tôi, phần tử giả bổ sung đã gây ra thay đổi chiều cao. Thêm tiêu cực margin-topvào ::afterkhối đã giải quyết điều đó.
Vaclav Novotny

2
Giải pháp này là tuyệt vời! Tôi đã sử dụng JS để thêm thuộc tính "data-content" có chứa văn bản của phần tử để tôi có thể tránh thay đổi HTML.
mistykristie

1
Tuyệt vời. Đây sẽ là câu trả lời tốt nhất. Lưu ý rằng nếu phần tử khác với li, bạn có thể phải sử dụng display: block; trên: sau phần tử cha.
Blackbam

Giải pháp tuyệt vời! Hoạt động tốt với :: trước đây cũng vậy, trong trường hợp của tôi, điều này ngăn chặn lợi nhuận bổ sung ở phía dưới.
Thomas Champion

Cảm ơn bạn cho giải pháp này. Ban đầu tôi đã sử dụng text-shadow nhưng điều này không hoạt động trong Safari vì nó làm tròn các giá trị thập phân. Vì tôi đang sử dụng 0,1px, giá trị này được làm tròn thành 0. Giải pháp của bạn hoạt động hoàn hảo. Tôi chỉ thay thế các thuộc tính tiêu đề với tên vì tôi không muốn các chú giải công cụ để hiển thị lên
Jonathan Cardoz

31

Giải pháp di động và dễ nhìn nhất sẽ là sử dụng text-shadow. Điều này sửa đổi và hiển thị các ví dụ về câu trả lời của Thorgeir bằng cách sử dụng các chỉnh sửa của Alexxali và của riêng tôi:

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

Điều này đặt các "bóng" nhỏ màu đen (sử dụng tên / mã màu của phông chữ của bạn thay thế blacknếu cần) trên cả hai mặt của mỗi chữ cái bằng cách sử dụng các đơn vị sẽ chia tỷ lệ phù hợp với kết xuất phông chữ.

cảnh báo Cảnh báo: px các giá trị có hỗ trợ các giá trị thập phân, nhưng chúng sẽ không đẹp như vậy khi kích thước phông chữ thay đổi (ví dụ: người dùng chia tỷ lệ chế độ xem bằng Ctrl+ +). Sử dụng các giá trị tương đối để thay thế.

Câu trả lời này sử dụng các phân số của exđơn vị vì chúng chia tỷ lệ với phông chữ.
Trong ~ hầu hết các mặc định của trình duyệt * , mong đợi 1ex8pxvà do đó 0.025ex0.1px.

Hãy tự mình xem:

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>

Di chuột qua các dòng được hiển thị để xem chúng khác với văn bản chuẩn như thế nào.

Thay đổi mức thu phóng của trình duyệt của bạn ( Ctrl+ +Ctrl+- ) để xem chúng khác nhau như thế nào.

Tôi đã thêm hai giải pháp khác ở đây để so sánh: thủ thuật giãn cách các chữ cái của @ cgTag , không hoạt động quá tốt vì nó liên quan đến việc đoán phạm vi độ rộng phông chữ và mẹo sau khi vẽ của @ workaholic_gangster911 , để lại khoảng trống khó xử để văn bản in đậm có thể mở rộng mà không di chuyển các mục văn bản lân cận (Tôi đặt ghi công sau văn bản in đậm để bạn có thể thấy nó không di chuyển như thế nào).


Trong tương lai, chúng tôi sẽ có nhiều phông chữ biến đổi hơn có khả năng thay đổi loại phông chữ thông qua font-variation-settings. Hỗ trợ trình duyệt đang tăng lên (Chrome 63+, Firefox 62+) nhưng điều này vẫn yêu cầu nhiều hơn là chỉ có phông chữ tiêu chuẩn và một số phông chữ hiện có hỗ trợ nó.

Nếu bạn nhúng một phông chữ thay đổi, bạn sẽ có thể sử dụng CSS như sau:

/* 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; }
}

Có một bản trình diễn trực tiếp với một thanh trượt để chơi với các cấp độ khác nhau trên Hướng dẫn Phông chữ Biến thể Mozilla. Giới thiệu của Google về các phông chữ có thể thay đổi trên web có một GIF động thể hiện sự chuyển đổi giữa loại cao và không có loại:

demo phông chữ Amstelvar Alpha hoạt hình với trục cấp chuyển đổi


1
Thật đơn giản, thật đẹp.
Randy Hall

18

Tôi nhận thấy rằng hầu hết các phông chữ đều có cùng kích thước khi bạn điều chỉnh khoảng cách giữa các chữ cái 1px.

a {
   letter-spacing: 1px;
}

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

Mặc dù điều này thay đổi phông chữ thông thường để mỗi chữ cái có thêm khoảng cách pixel. Đối với menu, tiêu đề quá ngắn, nó không phải là một vấn đề.


3
đây là giải pháp tốt nhất và được đánh giá thấp nhất, mặc dù tôi đã thay đổi nó để nó bắt đầu bằng 0 và chuyển sang khoảng cách chữ cái âm khi in đậm. Ngoài ra, bạn phải tinh chỉnh nó cho từng phông chữ và kích thước phông chữ. Tôi cũng đã cập nhật fiddle của @ Thorgeir để bao gồm điều này (như là giải pháp thứ 2) jsfiddle.net/dJcPn/50/
robotik

Các trình duyệt hiện đại hiện hỗ trợ độ chính xác của pixel phụ. Vì vậy, bạn có thể tinh chỉnh khoảng cách bằng cách sử dụng 0.98pxhoặc các phân số nhỏ hơn.
Reactgular

Điều này trông hơi kỳ lạ vì thuật toán giãn cách không hoàn toàn giống nhau (một số chữ cái nhảy xung quanh một chút) và quan trọng hơn, điều này không hoạt động khi phông chữ được chia tỷ lệ, ngay cả khi bạn chuyển đổi thành các 1pxgiá trị tương đối như 0.025exhoặc 0.0125ex. Xem câu trả lời của tôi cho một cuộc biểu tình trực tiếp.
Adam Katz

@AdamKatz Tôi nghi ngờ việc hiển thị phông chữ đã thay đổi kể từ khi câu trả lời này được đăng và nó phụ thuộc rất nhiều vào phông chữ bạn đang sử dụng.
Reactgular

5

Để có câu trả lời cập nhật hơn, bạn có thể sử dụng -webkit-text-stroke-width:

.element {
  font-weight: normal;
}

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

Điều này tránh mọi yếu tố giả (là một điểm cộng cho trình đọc màn hình) và bóng văn bản (trông lộn xộn và vẫn có thể tạo ra hiệu ứng 'nhảy' nhẹ) hoặc thiết lập bất kỳ độ rộng cố định nào (có thể không thực tế).

Nó cũng cho phép bạn đặt một phần tử đậm hơn 1px (về mặt lý thuyết, bạn có thể tạo phông chữ đậm tùy thích và cũng có thể là một bài tập kém chất lượng để tạo một phiên bản đậm của phông chữ không có chữ in đậm biến thể, chẳng hạn như phông chữ tùy chỉnh ( chỉnh sửa: phông chữ biến đổi làm giảm giá trị đề xuất này ). Mặc dù điều này nên tránh vì nó có thể làm cho một số phông chữ có vẻ xước và lởm chởm)

Tôi điều này chắc chắn hoạt động trong Edge, Firefox, Chrome và Opera (tại thời điểm đăng bài) và trong Safari ( chỉnh sửa: @Lars Blumberg, cảm ơn bạn đã xác nhận điều đó ). Nó KHÔNG hoạt động trong IE11 trở xuống.

Cũng lưu ý, nó sử dụng -webkittiền tố, vì vậy đây không phải là tiêu chuẩn và hỗ trợ có thể bị loại bỏ trong tương lai, vì vậy đừng dựa vào đây là chữ in đậm thực sự quan trọng - tốt nhất nên tránh kỹ thuật này trừ khi nó chỉ đơn thuần là thẩm mỹ.


1
Cũng hoạt động trên Safari 13.0.5. Giải pháp sạch nhất cho tôi cho đến nay.
Lars Blumberg

4

Thật không may, cách duy nhất để tránh thay đổi chiều rộng khi văn bản được in đậm là xác định chiều rộng của mục danh sách, tuy nhiên, như bạn đã nói làm điều này theo cách thủ công là tốn thời gian và không thể mở rộng.

Điều duy nhất tôi có thể nghĩ đến là sử dụng một số javascript để tính toán chiều rộng của tab trước khi nó được in đậm, và sau đó áp dụng chiều rộng đồng thời được yêu cầu in đậm (khi bạn di chuột hoặc nhấp vào).


hm, tôi sẽ thử nghiệm điều này, mặc dù tôi muốn nó ít nhất trông hợp lý (tức là được in đậm) cho người dùng không phải JS. Có lẽ tôi có thể gửi nó được in đậm, sử dụng JS để bỏ dấu nó, tính toán chiều rộng và sau đó in đậm lại? Hay đó chỉ là điều ngớ ngẩn?
Mala

Vâng, đó có vẻ là cách tốt nhất để thu hút người dùng không sử dụng javascript.
ajcw

2

Sử dụng JavaScript để đặt chiều rộng cố định của li dựa trên nội dung chưa được in đậm, sau đó in đậm nội dung bằng cách áp dụng một kiểu cho <a>thẻ (hoặc thêm khoảng cách nếu thẻ <li>không có bất kỳ phần tử nào).


Rất tiếc - xin lỗi vì lặp đi lặp lại: $
Dan Blows

Cảm ơn câu trả lời của bạn dù sao :)
Mala

@Mala Bạn đã tìm ra giải pháp chưa? Thật thú vị, tôi cũng có một vấn đề tương tự.
Dan Blows

1

Đây là một câu hỏi rất cũ, nhưng tôi đang xem lại vì tôi đã gặp sự cố này trong một ứng dụng mà tôi đang phát triển và tìm thấy tất cả các câu trả lời ở đây.

(Bỏ qua đoạn này vì TL; DR ...)Tôi đang sử dụng webfont của Gotham từ cloud.typography.com và tôi có các nút bắt đầu rỗng (với đường viền / văn bản màu trắng và nền trong suốt) và có được màu nền khi di chuột. Tôi nhận thấy rằng một số màu nền mà tôi đang sử dụng không tương phản tốt với văn bản màu trắng, vì vậy tôi muốn thay đổi văn bản thành màu đen cho các nút đó, nhưng - cho dù là do đánh lừa thị giác hay các phương pháp khử răng cưa thông thường - tối văn bản trên nền sáng dường như luôn có trọng lượng nhẹ hơn văn bản màu trắng trên nền tối. Tôi thấy rằng việc tăng trọng lượng từ 400 lên 500 cho văn bản tối duy trì gần như chính xác trọng lượng "trực quan". Tuy nhiên, nó đang tăng chiều rộng của nút lên một lượng nhỏ - một phần nhỏ của pixel - nhưng nó đủ để làm cho các nút có vẻ hơi "chập chờn", điều mà tôi muốn loại bỏ.

Giải pháp:

Rõ ràng, đây là một vấn đề thực sự khó khăn vì vậy nó đòi hỏi một giải pháp phức tạp. Cuối cùng, tôi đã sử dụng một tiêu cực letter-spacingtrên văn bản đậm hơn như cgTag được đề xuất ở trên, nhưng 1px sẽ là quá mức cần thiết, vì vậy tôi chỉ tính toán chính xác chiều rộng mà tôi cần.

Bằng cách kiểm tra nút trong Chrome devtools, tôi thấy rằng chiều rộng mặc định của nút là 165,47px và 165,69px khi di chuột, chênh lệch 0,22px. Nút có 9 ký tự, vì vậy:

0,22 / 9 = 0,024444px

Bằng cách chuyển đổi đơn vị đó sang đơn vị em, tôi có thể làm cho kích thước phông chữ điều chỉnh là bất khả tri. Nút của tôi đang sử dụng kích thước phông chữ là 16px, vì vậy:

0,024444 / 16 = 0,001527em

Vì vậy, cho phông chữ riêng của tôi, CSS sau đây giữ các nút chính xác cùng một chiều rộng trên di chuột:

.btn {
  font-weight: 400;
}

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

Với một chút thử nghiệm và sử dụng công thức ở trên, bạn có thể tìm thấy chính xác letter-spacinggiá trị phù hợp cho tình huống của mình và nó sẽ hoạt động bất kể kích thước phông chữ.

Một lưu ý là các trình duyệt khác nhau sử dụng các phép tính điểm ảnh phụ hơi khác nhau, vì vậy nếu bạn đang hướng tới mức độ chính xác hoàn hảo của điểm ảnh phụ OCD này, bạn sẽ cần lặp lại thử nghiệm và đặt một giá trị khác cho từng trình duyệt. Vì lý do chính đáng, các kiểu CSS nhắm mục tiêu theo trình duyệt thường không được ưa chuộng , nhưng tôi nghĩ đây là một trường hợp sử dụng mà nó là lựa chọn duy nhất có lý.


0

Câu hỏi thú vị. Tôi cho rằng bạn đang sử dụng float, phải không?

Chà, tôi không biết bạn có thể sử dụng bất kỳ kỹ thuật nào để loại bỏ việc phóng to phông chữ này, do đó họ sẽ cố gắng để vừa với chiều rộng tối thiểu cần thiết - và độ dày phông chữ thay đổi sẽ thay đổi giá trị này.

Giải pháp duy nhất mà tôi biết để tránh thay đổi này là một giải pháp mà bạn đã nói là bạn không muốn: đặt kích thước cố định thành li.


0

Bạn có thể thực hiện điều này như menu di chuột "Mua sắm theo bộ phận" của amazon.com. Nó sử dụng div rộng. Bạn có thể tạo div rộng và ẩn phần bên phải của nó


0

CẬP NHẬT: Phải sử dụng thẻ B cho tiêu đề vì trong IE11 lớp giả i: after không hiển thị khi tôi có khả năng hiển thị: ẩn.

Trong trường hợp của tôi, tôi muốn căn chỉnh hộp kiểm / radio đầu vào (được thiết kế tùy chỉnh) với văn bản nhãn trong đó văn bản được in đậm khi đầu vào được chọn.

Giải pháp được cung cấp ở đây không hoạt động với tôi trong Chrome. Việc căn chỉnh theo chiều dọc của đầu vào và nhãn bị rối với: lớp sau psuedo và -margins đã không khắc phục được điều này.

Đây là một bản sửa lỗi mà bạn không gặp khó khăn với căn chỉnh theo chiều dọc.

/* 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>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.