Введение
QSS задуман как кросс-платформенный механизм стилизации, но на практике итоговый визуальный результат может незначительно (а иногда и заметно) отличаться между Windows, macOS и Linux из-за различий в базовых стилях, шрифтовом рендеринге и поведении некоторых виджетов на разных платформах. В статье разберём конкретные источники таких различий и подходы к минимизации платформенной рассогласованности.
Концепция
QSS применяется поверх выбранного базового стиля (QStyle) — и если приложение использует платформенный нативный стиль по умолчанию (Windows Vista style на Windows, macOS style на Mac) вместо явно заданного кросс-платформенного Fusion, итоговый вид может заметно отличаться между платформами даже при идентичном QSS, поскольку часть визуальных аспектов (особенно тонкие детали отрисовки, не покрытые явно заданными QSS-свойствами) наследуется от платформенного стиля. Для максимально предсказуемого, одинакового на всех платформах вида обычно явно устанавливают стиль Fusion как базу, поверх которой QSS работает более последовательно.
Пример кода: QSS в многоплатформенных приложениях
#include <QApplication>
#include <QStyleFactory>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Явное указание кросс-платформенного стиля Fusion как основы —
// существенно снижает платформенные различия в применении QSS
app.setStyle(QStyleFactory::create("Fusion"));
app.setStyleSheet(R"(
QPushButton {
background-color: #2563eb;
color: white;
border-radius: 4px;
padding: 8px 16px;
font-family: "Segoe UI", "San Francisco", "Ubuntu", sans-serif;
}
)");
// ... остальной код приложения
return app.exec();
}
// Платформенно-зависимая корректировка стиля там, где полностью унифицировать невозможно
#include <QSysInfo>
QString platformSpecificAdjustments()
{
#if defined(Q_OS_MACOS)
// На macOS шрифты системы рендерятся визуально немного крупнее при том же размере в пунктах
return "QWidget { font-size: 12px; }";
#elif defined(Q_OS_WIN)
return "QWidget { font-size: 13px; }";
#else
return "QWidget { font-size: 13px; }";
#endif
}
void applyPlatformAwareStyle(QApplication &app, const QString &baseStyleSheet)
{
app.setStyleSheet(baseStyleSheet + platformSpecificAdjustments());
}
Пояснения к коду
Явный вызов QStyleFactory::create("Fusion") гарантирует, что приложение использует один и тот же базовый алгоритм отрисовки виджетов на всех платформах, вместо платформенно-специфичных стилей по умолчанию — это первый и самый важный шаг к визуальному единообразию между ОС. Список шрифтов через запятую в font-family ("Segoe UI", "San Francisco", "Ubuntu", sans-serif) показывает практику явного указания предпочитаемого шрифта для каждой платформы с fallback — Qt применит первый шрифт из списка, который доступен в системе, и в конце концов упадёт на обобщённый sans-serif, если ни один из конкретных вариантов не найден.
platformSpecificAdjustments() показывает осознанный, явный подход к минимальным платформенным корректировкам там, где полная унификация недостижима или нежелательна (например, известная разница в визуальном восприятии размера шрифта между macOS и Windows при формально одинаковом значении в пунктах) — такие корректировки должны быть осознанными исключениями, явно задокументированными в коде через комментарии, а не случайными артефактами недостаточного тестирования на разных платформах.
Подводные камни
- Тестирование QSS только на одной платформе разработки (часто Windows или Linux) без проверки на остальных целевых платформах — поскольку именно платформенные различия в рендеринге шрифтов, поведении некоторых псевдосостояний и деталях нативного стиля могут проявиться только при реальном запуске на другой ОС, регулярная проверка внешнего вида на каждой целевой платформе должна быть частью обычного процесса разработки кросс-платформенного приложения, а не разовой финальной проверкой перед релизом.
- Шрифты, доступные на одной платформе, могут отсутствовать на другой — жёстко закодированное указание единственного, специфичного для одной ОС шрифта (например, «Segoe UI» без альтернатив) приводит к тому, что на других платформах, где этот шрифт недоступен, Qt подставит совершенно другой шрифт по своему выбору, что может выглядеть не так, как задумывалось дизайном; список альтернатив с fallback, как в примере, существенно снижает этот риск.
- HiDPI/масштабирование экрана обрабатывается по-разному на разных платформах, и фиксированные пиксельные значения в QSS (отступы, размеры в
px) могут визуально выглядеть по-разному при разной плотности пикселей экрана конкретного устройства — для приложений, ориентированных на широкий спектр экранов с разной плотностью пикселей, стоит проверять вид интерфейса именно на HiDPI-дисплеях, а не предполагать автоматическую идеальную масштабируемость всех QSS-размеров. - Различное поведение системных диалогов (выбора файла, цвета, печати) между платформами, не подчиняющихся кастомному QSS-стилю приложения вовсе (аналогично подводному камню из статьи 265 про темы) — на одной платформе системный диалог может визуально хорошо сочетаться с остальным кастомизированным интерфейсом, а на другой — выглядеть совершенно инородно, и эта рассогласованность находится за пределами того, что можно исправить через сам QSS приложения.