* { margin: 0; padding: 0; box-sizing: border-box; } html, body { height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; background: #f5f5f5; overflow: hidden; -webkit-user-select: none; user-select: none; } .app { display: flex; flex-direction: column; height: 100vh; } /* 顶部工具栏 */ .toolbar { display: flex; justify-content: center; align-items: center; gap: 6px; padding: 10px 12px; background: #fff; border-bottom: 1px solid #e0e0e0; flex-shrink: 0; } .btn { min-width: 68px; height: 36px; padding: 0 10px; font-size: 14px; border: 1px solid #ddd; border-radius: 6px; background: #fff; color: #333; cursor: pointer; transition: all 0.2s; white-space: nowrap; display: flex; align-items: center; justify-content: center; } .btn:active { background: #f0f0f0; } .btn-primary { min-width: 100px; background: #4a90e2; color: #fff; border-color: #4a90e2; } .btn-primary:active { background: #3a7bc8; } /* 工具栏垂直分隔线 */ .toolbar-divider-v { width: 1px; height: 20px; background: #e0e0e0; margin: 0 2px; } /* 工具栏图标按钮 */ .toolbar-btn-icon { width: 28px; height: 28px; font-size: 14px; border: 1px solid #ddd; border-radius: 5px; background: #fff; color: #555; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; padding: 0; } .toolbar-btn-icon:hover { background: #f5f5f5; border-color: #ccc; } .toolbar-btn-icon:active { background: #e8e8e8; } .toolbar-btn-icon:disabled { opacity: 0.3; cursor: not-allowed; background: #f5f5f5; } /* 撤销重做按钮组 */ .toolbar-action-group { display: flex; gap: 3px; margin: 0 2px; } /* 左侧分隔线(文本按钮后) */ .toolbar-divider-v.divider-left { margin-left: 4px; margin-right: 0; } /* 右侧分隔线(保存按钮前) */ .toolbar-divider-v.divider-right { margin-left: 0; margin-right: 4px; } /* 撤销重做按钮组 */ .toolbar-action-group { display: flex; gap: 3px; margin: 0; } /* 保存/预览按钮 */ .btn-primary { min-width: 80px; height: 36px; padding: 0 14px; font-size: 14px; } /* 文本输入框删除按钮 */ .text-input .text-delete-btn { position: absolute; top: -10px; right: -10px; width: 20px; height: 20px; background: #e74c3c; color: #fff; border: none; border-radius: 50%; font-size: 12px; line-height: 20px; text-align: center; cursor: pointer; display: none; z-index: 10; } .text-input.selected:not(.editing) .text-delete-btn { display: block; } /* 编辑器工具栏(文本/图片共用) */ .editor-toolbar { position: absolute; top: 65px; left: 0; right: 0; display: flex; justify-content: center; align-items: center; padding: 8px 12px; background: #fff; border-bottom: 1px solid #e0e0e0; flex-shrink: 0; visibility: hidden; opacity: 0; transition: opacity 0.2s; z-index: 100; } /* 编辑模式:粘在视口顶部始终可见 */ .editor-toolbar.editing-mode { position: fixed; top: 0; border-bottom: 1px solid #e0e0e0; box-shadow: 0 2px 10px rgba(0,0,0,0.1); z-index: 10000; } /* 移动端:允许横向滚动 */ @media (max-width: 768px) { .editor-toolbar { justify-content: flex-start; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; padding: 8px; } .editor-toolbar::-webkit-scrollbar { display: none; } .toolbar-group { gap: 2px; flex-shrink: 0; width: 100%; justify-content: center; } .toolbar-btn { width: 32px; height: 32px; font-size: 14px; } .toolbar-label { font-size: 12px; } .toolbar-label span:first-child { display: inline; } .roller-picker { min-width: 50px; height: 32px; padding: 2px 4px; } } .editor-toolbar.active { visibility: visible; opacity: 1; } .toolbar-group { display: none; justify-content: center; align-items: center; gap: 2px; width: 100%; } .toolbar-group.active { display: flex; } .toolbar-btn { width: 36px; height: 36px; font-size: 16px; font-weight: bold; border: 1px solid #ddd; border-radius: 6px; background: #fff; color: #333; cursor: pointer; transition: all 0.2s; } .toolbar-btn:active { background: #f0f0f0; } .toolbar-btn.active { background: #4a90e2; color: #fff; border-color: #4a90e2; } .toolbar-btn.italic { font-style: italic; } /* 镜像按钮样式 */ .toolbar-btn.mirror-btn { width: 30px; height: 30px; font-size: 16px; } .toolbar-divider { width: 1px; height: 24px; background: #ddd; margin: 0 1px; } .toolbar-label { display: flex; align-items: center; gap: 2px; font-size: 12px; color: #666; } .toolbar-label select { padding: 4px 6px; font-size: 12px; border: 1px solid #ddd; border-radius: 4px; background: #fff; cursor: pointer; } .opacity-slider { width: 100px; height: 32px; cursor: pointer; accent-color: #4a90e2; margin: 0; } .scale-slider { width: 100px; height: 32px; cursor: pointer; accent-color: #4a90e2; margin: 0; } .rotate-slider { width: 100px; height: 32px; cursor: pointer; accent-color: #4a90e2; margin: 0; } /* 旋转度数显示固定宽度 */ #rotateValue { display: inline-block; min-width: 40px; text-align: center; } /* 百分比显示固定宽度 */ #opacityValue, #bgScaleValue, #bgOpacityValue { display: inline-block; min-width: 40px; text-align: center; } /* 字号滚轮选择器 */ .roller-picker { display: flex; align-items: center; gap: 4px; padding: 4px 8px; background: #fff; border: 1px solid #ddd; border-radius: 6px; min-width: 65px; height: 36px; } .roller-arrow { font-size: 10px; color: #666; cursor: pointer; padding: 2px 4px; user-select: none; transition: color 0.2s; } .roller-arrow:hover { color: #4a90e2; } .roller-value { font-size: 14px; min-width: 24px; text-align: center; color: #333; } #fontPicker { min-width: 55px; } .toolbar-label input[type="color"] { width: 36px; height: 36px; padding: 2px; border: 1px solid #ddd; border-radius: 6px; cursor: pointer; } /* 图片展示区 */ .canvas-area { flex: 1; display: flex; align-items: center; justify-content: center; padding: 16px; overflow: auto; position: relative; } /* 空提示 - 移到预览白板中 */ .empty-tip { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #999; font-size: 14px; text-align: center; pointer-events: none; z-index: 5; } /* 预览区域固定 3:5 比例,打开即显示空白面板 */ .preview { overflow: hidden; } .image-container { display: flex; position: relative; width: 100%; max-width: 360px; aspect-ratio: 960 / 1361; box-shadow: 0 4px 20px rgba(0,0,0,0.15); background: #fff; overflow: hidden; touch-action: pan-x; margin: 0 auto; contain: layout style paint; } .image-container.empty { background: #f0f0f0; border: 2px dashed #ddd; } /* 背景图层 - 用于滑动调整位置,溢出隐藏 */ .preview-bg-layer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; } /* 层叠图层 - 位于背景图之上、文字之下、提示文字之上 */ .overlay-layer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 6; } .overlay-layer .overlay-image { position: absolute; pointer-events: auto; cursor: move; touch-action: none; } .overlay-layer .overlay-image.selected { outline: 2px dashed rgba(74, 144, 226, 0.8); outline-offset: 2px; } .overlay-layer .overlay-image .resize-handle { display: none; } .overlay-layer .overlay-image.selected .resize-handle { display: block; } .overlay-layer .overlay-image .delete-btn { position: absolute; top: -10px; right: -10px; width: 20px; height: 20px; background: #e74c3c; color: #fff; border: none; border-radius: 50%; font-size: 12px; line-height: 20px; text-align: center; cursor: pointer; display: none; z-index: 10; } .overlay-layer .overlay-image.selected .delete-btn { display: block; } /* 输入框图层 - 与背景图层隔离 */ .preview-input-layer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 7; } /* 输入框可交互 */ .preview-input-layer .text-input { pointer-events: auto; z-index: 8; } /* 背景图 - 保持比例,可滑动调整位置 */ #bgImage { display: block; position: absolute; max-width: none; -webkit-user-drag: none; } #bgImage[src=""] { display: none; } /* 文字输入框 - 透明无边框设计,黑色微软雅黑16px */ .text-input { position: absolute; min-width: 80px; min-height: 32px; padding: 0; font-size: 16px; color: #000; font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif; background: transparent; outline: 2px solid transparent; border-radius: 4px; cursor: grab; white-space: nowrap; line-height: 1.4; -webkit-user-select: none; user-select: none; transition: outline-color 0.2s; z-index: 10; overflow: visible; max-width: none; box-sizing: border-box; font-weight: bold; } /* 选中状态(单击/长按) - 仅显示虚线轮廓 */ .text-input.selected { outline: 2px dashed rgba(74, 144, 226, 0.6); cursor: grab; } /* 锁定状态 */ .text-input.locked { cursor: default !important; } .text-input.locked.selected { outline: 2px dashed rgba(255, 193, 7, 0.8); } .text-input.locked .text-delete-btn { display: none !important; } /* 空输入框显示 placeholder */ .text-input.show-placeholder::before { content: attr(data-placeholder); color: #999; pointer-events: none; } /* 编辑状态(双击) - 显示实线轮廓 */ .text-input.editing { outline: 2px solid #4a90e2; background: rgba(255,255,255,0.1); cursor: text; -webkit-user-select: text; user-select: text; -webkit-touch-callout: default; pointer-events: auto; } /* 拖拽状态 */ .text-input.dragging { opacity: 0.8; cursor: grabbing; } /* 隐藏元素 */ .hidden { display: none !important; } /* 隐藏空提示 */ .empty-tip.hidden { display: none; } /* 右键菜单 */ .context-menu { position: fixed; background: #fff; border: 1px solid #ddd; border-radius: 6px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); padding: 4px 0; z-index: 1000; min-width: 140px; } .context-menu-item { padding: 10px 16px; font-size: 14px; color: #333; cursor: pointer; transition: background 0.2s; } .context-menu-item:hover { background: #f5f5f5; } .context-menu-item:active { background: #e8e8e8; } /* 拖拽辅助线 */ .guide-line { position: absolute; pointer-events: none; z-index: 1000; display: none; } .guide-horizontal { left: 0; right: 0; height: 1px; background: #e74c3c; box-shadow: 0 0 4px rgba(231, 76, 60, 0.5); } .guide-vertical { top: 0; bottom: 0; width: 1px; background: #e74c3c; box-shadow: 0 0 4px rgba(231, 76, 60, 0.5); } .guide-line.visible { display: block; } /* 1px 网格线 */ .grid-lines { position: absolute; top: 0; left: 0; right: 0; bottom: 0; pointer-events: none; z-index: 5; display: none; background-image: linear-gradient(to right, rgba(0, 0, 0, 0.05) 1px, transparent 1px), linear-gradient(to bottom, rgba(0, 0, 0, 0.05) 1px, transparent 1px); background-size: 10px 10px; } .grid-lines.visible { display: block; } /* ==================== 图层面板样式 ==================== */ .layers-panel { position: fixed; top: 60px; right: -280px; width: 260px; height: calc(100vh - 80px); background: #fff; border-left: 1px solid #e0e0e0; box-shadow: -2px 0 10px rgba(0,0,0,0.1); z-index: 200; display: flex; flex-direction: column; transition: right 0.3s ease; } .layers-panel.active { right: 0; } .layers-header { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-bottom: 1px solid #e0e0e0; background: #f8f8f8; } .layers-title { font-size: 14px; font-weight: 600; color: #333; } .layers-close { width: 24px; height: 24px; border: none; background: transparent; font-size: 18px; color: #666; cursor: pointer; display: flex; align-items: center; justify-content: center; border-radius: 4px; transition: all 0.2s; } .layers-close:hover { background: #e0e0e0; color: #333; } .layers-list { flex: 1; overflow-y: auto; padding: 8px; } .layer-item { display: flex; align-items: center; padding: 10px 12px; margin-bottom: 4px; background: #f5f5f5; border-radius: 6px; cursor: pointer; transition: all 0.2s; border: 2px solid transparent; } .layer-item:hover { background: #e8e8e8; } .layer-item.selected { background: #e3f2fd; border-color: #4a90e2; } .layer-item.hidden { opacity: 0.5; display: flex !important; } .layer-icon { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; margin-right: 10px; font-size: 14px; } .layer-info { flex: 1; min-width: 0; } .layer-name { font-size: 13px; color: #333; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .layer-type { font-size: 11px; color: #999; margin-top: 2px; } .layer-visibility { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: bold; cursor: pointer; padding: 4px; border-radius: 4px; transition: all 0.2s; background: #4CAF50; color: white; border: 2px solid transparent; } .layer-visibility.is-hidden { background: #f44336; color: white; } .layer-visibility:hover { opacity: 0.8; transform: scale(1.1); } .layer-visibility:active { transform: scale(0.95); } .layers-actions { display: flex; align-items: center; justify-content: center; gap: 4px; padding: 12px; border-top: 1px solid #e0e0e0; background: #f8f8f8; flex-wrap: wrap; } .layers-btn { width: 32px; height: 32px; border: 1px solid #ddd; background: #fff; border-radius: 4px; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; transition: all 0.2s; } .layers-btn:hover { background: #f0f0f0; border-color: #ccc; } .layers-btn:disabled { opacity: 0.3; cursor: not-allowed; } .layers-btn-danger:hover { background: #ffebee; border-color: #ef5350; } .layers-divider { width: 1px; height: 24px; background: #ddd; margin: 0 4px; } /* 图层隐藏状态(用于画布上的元素) */ .layer-hidden { visibility: hidden !important; pointer-events: none !important; } /* 移动端适配 */ @media (max-width: 768px) { .layers-panel { width: 240px; right: -260px; top: 50px; height: calc(100vh - 50px); } .layers-actions { padding: 8px; } .layers-btn { width: 28px; height: 28px; font-size: 12px; } }