banner
innei

innei

写代码是因为爱,写到世界充满爱!
github
telegram
twitter

CSS implementation of text overflow Clip does not truncate half a character

Recently, a colleague asked me if CSS can truncate text overflow without cutting off individual characters. Usually, we use text-overflow: clip; overflow: hidden to achieve this. However, in many cases, this situation occurs.

The text behind is truncated

I thought about it and it seems like it's not feasible. If it were me, I would calculate the width using JavaScript and then determine how many complete characters should be displayed. If it can't be done, I can only compromise with the UI.

Suddenly, I had a flash of inspiration. What if we consider how normal line breaks work? Normal line breaks don't result in half-cut characters, and they can also break lines based on punctuation.

image

So, as long as we find a way to only display the first line, it should work. Therefore, we just need to add a maximum height to the outer container, which is the height of the first line of text, and remove white-space: nowrap; text-overflow: clip;. Then, it will work perfectly.

And by writing it this way, no matter what the text is, there won't be any issues with cutting off half of it. As for the height of the text container, it is usually provided in the UI design, so you can just copy it. This is the simplest way. It works for two lines as well. It works for any number of lines.

This method also applies to React Native.

The above image shows the effect in RN 0.69. The top part shows the effect using this method, while the bottom part shows the effect using clip directly.

import { StatusBar } from 'expo-status-bar'
import { Dimensions, StyleSheet, Text, View } from 'react-native'

export default function App() {
  return (
    <View style={styles.container}>
      <View style={styles.padding} />
      <View>
        <View style={styles.flexContainer}>
          <Text
            style={styles.text}
            numberOfLines={4}
            lineBreakMode="clip"
            ellipsizeMode="clip"
          >
            The swallows have left, but they will return when the time comes. The willows have withered, but they will turn green again. The peach blossoms have fallen, but they will bloom again. However, wise one, tell me, why can't our days come back? —— Did someone steal them? Who was it? Where are they hiding? Did they run away by themselves? Where are they now?
          </Text>
        </View>
        <View style={styles.padding}></View>
        <View style={[styles.flexContainer, { height: 48 }]}>
          <Text
            ellipsizeMode="clip"
            numberOfLines={2}
            style={{ fontSize: 24, lineHeight: 24 }}
          >
            The swallows have left, but they will return when the time comes. The willows have withered, but they will turn green again. The peach blossoms have fallen, but they will bloom again. However, wise one, tell me, why can't our days come back? —— Did someone steal them? Who was it? Where are they hiding? Did they run away by themselves? Where are they now?
          </Text>
        </View>
      </View>

      <StatusBar style="auto" />
    </View>
  )
}

const styles = StyleSheet.create({
  flexContainer: {
    // width: 350,
    // alignItems: 'flex-start',
    // justifyContent: 'flex-start',
    height: 46,
    overflow: 'hidden',
  },
  text: {
    fontSize: 24,
    lineHeight: 24,
    height: Dimensions.get('window').height,   // Note this (must be specified)
  },
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  padding: {
    height: 80,
    backgroundColor: '#12222233',
    marginVertical: 12,
  },
})

The code is attached. Note that the height of the Text component in RN must be specified, otherwise it will inherit the height of the parent element and won't work properly. It is recommended to directly set it to the height of the device.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.