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.