SymbolFYI

Fullwidth & Halfwidth

Typography
Định nghĩa

Character variants occupying different widths in CJK typography. Fullwidth characters occupy the same space as CJK ideographs.

Fullwidth characters are Unicode code points that occupy the same horizontal width as CJK (Chinese, Japanese, Korean) ideographs -- typically twice the width of standard Latin characters. They allow Latin letters, digits, and punctuation to be used within East Asian text while maintaining consistent grid-based alignment, which is essential for the monospaced column layouts traditionally used in those typographic systems.

The East Asian Width Property

Every Unicode character has an East Asian Width property with one of several values:

  • Fullwidth (F) -- always double-width: fullwidth ASCII variants
  • Wide (W) -- always double-width: CJK ideographs, most East Asian characters
  • Halfwidth (H) -- always single-width: halfwidth Katakana, halfwidth forms
  • Narrow (Na) -- always single-width: ASCII, Latin letters
  • Ambiguous (A) -- depends on context/locale
  • Neutral (N) -- no strong preference

Fullwidth ASCII Variants

Unicode provides fullwidth versions of all printable ASCII characters in the range U+FF01 to U+FF60:

U+FF01  FULLWIDTH EXCLAMATION MARK
U+FF10  FULLWIDTH DIGIT ZERO
U+FF21  FULLWIDTH LATIN CAPITAL LETTER A
U+FF41  FULLWIDTH LATIN SMALL LETTER A
U+FF0E  FULLWIDTH FULL STOP
U+FF1A  FULLWIDTH COLON

The fullwidth range provides double-width versions of digits 0-9, uppercase A-Z, and lowercase a-z.

CSS Handling

/* Font selection for CJK text -- these fonts correctly render both
   fullwidth and halfwidth characters */
.cjk-text {
  font-family: 'Hiragino Sans', 'Yu Gothic', 'Noto Sans CJK JP', sans-serif;
}

/* The font-feature-settings 'pwid' converts fullwidth to proportional width
   in fonts that support it */
.proportional-width {
  font-feature-settings: 'pwid' 1;
}

/* 'fwid' forces fullwidth form */
.force-fullwidth {
  font-feature-settings: 'fwid' 1;
}

Detecting Fullwidth Characters in JavaScript

// Check if a character is fullwidth
function isFullwidth(char) {
  const code = char.codePointAt(0);
  return (
    (code >= 0xFF01 && code <= 0xFF60) || // Fullwidth ASCII
    (code >= 0x4E00 && code <= 0x9FFF) || // CJK Unified Ideographs
    (code >= 0x3000 && code <= 0x303F)    // CJK Symbols and Punctuation
  );
}

// Get visual width of a string (counting fullwidth as 2)
function visualWidth(str) {
  let width = 0;
  for (const char of str) {
    width += isFullwidth(char) ? 2 : 1;
  }
  return width;
}

// Convert fullwidth digits to halfwidth
function normalizeFullwidth(str) {
  return str.replace(/[\uFF01-\uFF60]/g, (c) =>
    String.fromCharCode(c.charCodeAt(0) - 0xFEE0)
  );
}
// normalizeFullwidth('012 in fullwidth') -> '012 in fullwidth'

When Fullwidth Characters Appear in User Input

Users on East Asian keyboard layouts frequently type fullwidth characters unintentionally. Input Method Editors (IMEs) may produce fullwidth digits and punctuation. Forms accepting phone numbers, postal codes, or prices must handle fullwidth normalization:

// Normalize fullwidth to ASCII for form validation
function normalizeInput(value) {
  // Fullwidth ASCII to ASCII
  return value.replace(/[\uFF01-\uFF60]/g, (c) =>
    String.fromCharCode(c.charCodeAt(0) - 0xFEE0)
  // Ideographic space to regular space
  ).replace(/\u3000/g, ' ');
}

Terminal and Monospace Rendering

In terminal applications and monospace code editors, correctly accounting for fullwidth character widths is important for alignment. A fullwidth character that is treated as single-width will cause column alignment to shift by one position for every such character. Libraries like wcwidth implement the POSIX wcwidth() function to report the correct column width.

Ký hiệu liên quan

Thuật ngữ liên quan

Công cụ liên quan