iOS Fabric: fontFamily (PostScript name) + explicit fontWeight resolves to the heaviest face — elvis-operator typo in RCTFontUtils.mm
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 1/5
- Temps estimé
- Moins d'une heure
- Accessibilité débutants
- 85/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- ios, objective-c, react-native
- Domaine
- mobile-dev
Piste de recherche
Commencez dans ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm vers la ligne 364 et examinez comment les graisses de police explicites sont sélectionnées. Reproduisez le problème avec les exemples Poppins PostScript-name et examinez les runs de police NSAttributedString rendus. Le travail est terminé lorsque les graisses explicites non par défaut sont résolues vers la variante demandée plutôt que vers la variante la plus lourde.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Description
On iOS/Fabric in React Native 0.86.2, any <Text> style that combines a PostScript-named fontFamily with an explicit non-default fontWeight renders the heaviest face in the family instead of the requested weight.
// Renders Poppins-Medium (correct)
<Text style={{ fontFamily: 'Poppins-Medium' }} />
// Renders Poppins-Bold (bug — expected Poppins-Medium)
<Text style={{ fontFamily: 'Poppins-Medium', fontWeight: '500' }} />
// Renders Poppins-Bold (bug — expected Poppins-SemiBold)
<Text style={{ fontFamily: 'Poppins-SemiBold', fontWeight: '600' }} />
// Bare family name + weight resolves correctly (different code path)
<Text style={{ fontFamily: 'Poppins', fontWeight: '500' }} /> // correct
Verified via the rendered NSAttributedString font runs (not UIFont lookups): the fonts are registered and loadable; the resolver selects the wrong face.
Root cause
ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm (~line 364):
fontWeight = (fontWeight != 0.0) ?: RCTGetFontWeight(font);
The GNU ?: (elvis) operator assigns the boolean result of the comparison — 1.0 — for any explicit nonzero weight, rather than preserving the original fontWeight value. UIFontWeight 1.0 is the heaviest weight, so the subsequent family search selects the boldest face.
Suggested fix
fontWeight = (fontWeight != 0.0) ? fontWeight : RCTGetFontWeight(font);
(Note: this still cannot distinguish an explicit fontWeight: '400' from "no weight," since UIFontWeightRegular == 0.0 — a separate, pre-existing limitation.)
Impact
Any app pairing custom-font PostScript names with explicit weights (a common pattern, and the style many older codebases carry from pre-Fabric versions where the named face won) renders bold text across the board after upgrading. We hit this migrating a production app from 0.81.5 to 0.86.2 — every fontFamily: 'Poppins-<Face>' + matching fontWeight pair (~450 style sites) collapsed to Poppins-Bold. We are carrying a one-line patch-package fix of the ternary, which restores correct resolution for all pairings.
Steps to reproduce
- Bundle a multi-weight custom font family (e.g. Poppins Regular/Medium/SemiBold/Bold) via
UIAppFonts. - Render
<Text style={{ fontFamily: 'Poppins-Medium', fontWeight: '500' }}>test</Text>on 0.86.2 with Fabric. - Inspect the rendered attributed string: the resolved font is
Poppins-Bold.
Environment
React Native 0.86.2 (Fabric / new architecture), iOS 26.5 simulator + device, Expo SDK 57 prebuild (bare workflow equivalent). Regression vs 0.81.5 behavior.
- Langage dominant
- C++
- Étoiles
- 127k
- Forks
- 25.3k
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de react/react-native
-
Needs: Author Feedback Needs: Repro
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
react/react-native#58659 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
Needs: Author Feedback Needs: Repro
Difficulté 1/5 Moins d'une heure Accessibilité débutants 92/100
react/react-native#58621 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Needs: Attention Needs: Repro
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
react/react-native#58610 · 3 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
Needs: Triage :mag:
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
react/react-native#58565 · 1 commentaire · 2 réactions ·
Les mainteneurs répondent en général sous 1 jour
-
Needs: Attention Needs: Repro
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
react/react-native#58526 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de react/react-native
Issues similaires
-
bug chart-audit
Difficulté 1/5 Moins d'une heure Accessibilité débutants 92/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
godotengine/godot#124120 ·
Les mainteneurs répondent en général sous 1 jour
-
Component: R Type: bug
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
apache/arrow#51695 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
HasBacktrace Priority-Critical
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
azerothcore/azerothcore-wotlk#27921 ·
Les mainteneurs répondent en général sous 1 jour
-
area/ysql kind/bug priority/medium
Difficulté 2/5 1-3 heures Accessibilité débutants 86/100
yugabyte/yugabyte-db#34584 ·
Les mainteneurs répondent en général sous 1 jour